Merge "Revert "Publish DevicePolicyManager CA certificate APIs""
diff --git a/Android.mk b/Android.mk
index 4875cc5..216d8a2d4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -77,9 +77,9 @@
 	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/ITaskManager.aidl \
-	core/java/android/app/task/ITaskService.aidl \
+	core/java/android/app/job/IJobCallback.aidl \
+	core/java/android/app/job/IJobScheduler.aidl \
+	core/java/android/app/job/IJobService.aidl \
 	core/java/android/app/IThumbnailRetriever.aidl \
 	core/java/android/app/ITransientNotification.aidl \
 	core/java/android/app/IUiAutomationConnection.aidl \
@@ -94,10 +94,10 @@
 	core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreSession.aidl \
-	core/java/android/app/maintenance/IIdleCallback.aidl \
-	core/java/android/app/maintenance/IIdleService.aidl \
 	core/java/android/bluetooth/IBluetooth.aidl \
 	core/java/android/bluetooth/IBluetoothA2dp.aidl \
+	core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
+	core/java/android/bluetooth/IBluetoothAvrcpController.aidl \
 	core/java/android/bluetooth/IBluetoothCallback.aidl \
 	core/java/android/bluetooth/IBluetoothHeadset.aidl \
 	core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
@@ -110,6 +110,7 @@
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
 	core/java/android/bluetooth/IBluetoothMap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
+	core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
 	core/java/android/bluetooth/IBluetoothGatt.aidl \
 	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
 	core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
@@ -149,6 +150,7 @@
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
+	core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
@@ -341,6 +343,7 @@
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
+	telephony/java/com/android/internal/telephony/ISub.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
@@ -605,8 +608,12 @@
 framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
 # The since flag (-since N.xml API_LEVEL) is used to add API Level information
 # to the reference documentation. Must be in order of oldest to newest.
+#
+# Conscrypt (com.android.org.conscrypt) is an implementation detail and should
+# not be referenced in the documentation.
 framework_docs_LOCAL_DROIDDOC_OPTIONS := \
     -knowntags ./frameworks/base/docs/knowntags.txt \
+    -hidePackage com.android.org.conscrypt \
     -since $(SRC_API_DIR)/1.xml 1 \
     -since $(SRC_API_DIR)/2.xml 2 \
     -since $(SRC_API_DIR)/3.xml 3 \
@@ -700,7 +707,7 @@
 $(INTERNAL_PLATFORM_API_FILE): $(full_target)
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
 
-# ====  the private api stubs ===================================
+# ====  the system api stubs ===================================
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
@@ -712,11 +719,11 @@
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
 LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 
-LOCAL_MODULE := private-api-stubs
+LOCAL_MODULE := system-api-stubs
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-		-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_private_stubs_current_intermediates/src \
+		-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_system_stubs_current_intermediates/src \
         -showAnnotation android.annotation.SystemApi \
 		-nodocs
 
diff --git a/CleanSpec.mk b/CleanSpec.mk
index f3bb9b6..1968a78 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -34,9 +34,9 @@
 # made today requires touching the same file, just copy the old
 # touch step and add it to the end of the list.
 #
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
 
 # For example:
 #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
@@ -193,7 +193,16 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/task)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/task)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/TaskManager)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/maintenance)
 
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/api/current.txt b/api/current.txt
index 474d5b2..af989e8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -320,6 +320,8 @@
     field public static final int backgroundDimEnabled = 16843295; // 0x101021f
     field public static final int backgroundSplit = 16843659; // 0x101038b
     field public static final int backgroundStacked = 16843658; // 0x101038a
+    field public static final int backgroundTint = 16843885; // 0x101046d
+    field public static final int backgroundTintMode = 16843886; // 0x101046e
     field public static final int backupAgent = 16843391; // 0x101027f
     field public static final int banner = 16843762; // 0x10103f2
     field public static final int baseline = 16843548; // 0x101031c
@@ -344,6 +346,8 @@
     field public static final int buttonStyleInset = 16842826; // 0x101004a
     field public static final int buttonStyleSmall = 16842825; // 0x1010049
     field public static final int buttonStyleToggle = 16842827; // 0x101004b
+    field public static final int buttonTint = 16843889; // 0x1010471
+    field public static final int buttonTintMode = 16843890; // 0x1010472
     field public static final int cacheColorHint = 16843009; // 0x1010101
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
@@ -554,6 +558,8 @@
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
+    field public static final int foregroundTint = 16843887; // 0x101046f
+    field public static final int foregroundTintMode = 16843888; // 0x1010470
     field public static final int format = 16843013; // 0x1010105
     field public static final int format12Hour = 16843722; // 0x10103ca
     field public static final int format24Hour = 16843723; // 0x10103cb
@@ -636,6 +642,8 @@
     field public static final int indeterminateDuration = 16843069; // 0x101013d
     field public static final int indeterminateOnly = 16843066; // 0x101013a
     field public static final int indeterminateProgressStyle = 16843544; // 0x1010318
+    field public static final int indeterminateTint = 16843883; // 0x101046b
+    field public static final int indeterminateTintMode = 16843884; // 0x101046c
     field public static final int indicatorEnd = 16843730; // 0x10103d2
     field public static final int indicatorLeft = 16843021; // 0x101010d
     field public static final int indicatorRight = 16843022; // 0x101010e
@@ -859,6 +867,7 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
+    field public static final int overlapAnchor = 16843876; // 0x1010464
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
     field public static final int padding = 16842965; // 0x10100d5
@@ -910,6 +919,8 @@
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
     field public static final int progress = 16843063; // 0x1010137
+    field public static final int progressBackgroundTint = 16843879; // 0x1010467
+    field public static final int progressBackgroundTintMode = 16843880; // 0x1010468
     field public static final int progressBarPadding = 16843545; // 0x1010319
     field public static final int progressBarStyle = 16842871; // 0x1010077
     field public static final int progressBarStyleHorizontal = 16842872; // 0x1010078
@@ -920,6 +931,8 @@
     field public static final int progressBarStyleSmallInverse = 16843400; // 0x1010288
     field public static final int progressBarStyleSmallTitle = 16843279; // 0x101020f
     field public static final int progressDrawable = 16843068; // 0x101013c
+    field public static final int progressTint = 16843877; // 0x1010465
+    field public static final int progressTintMode = 16843878; // 0x1010466
     field public static final int prompt = 16843131; // 0x101017b
     field public static final int propertyName = 16843489; // 0x10102e1
     field public static final int protectionLevel = 16842761; // 0x1010009
@@ -1000,6 +1013,9 @@
     field public static final int scrollbars = 16842974; // 0x10100de
     field public static final int scrollingCache = 16843006; // 0x10100fe
     field public static final deprecated int searchButtonText = 16843269; // 0x1010205
+    field public static final int searchKeyphrase = 16843873; // 0x1010461
+    field public static final int searchKeyphraseId = 16843872; // 0x1010460
+    field public static final int searchKeyphraseSupportedLocales = 16843874; // 0x1010462
     field public static final int searchMode = 16843221; // 0x10101d5
     field public static final int searchSettingsDescription = 16843402; // 0x101028a
     field public static final int searchSuggestAuthority = 16843222; // 0x10101d6
@@ -1009,6 +1025,8 @@
     field public static final int searchSuggestSelection = 16843224; // 0x10101d8
     field public static final int searchSuggestThreshold = 16843373; // 0x101026d
     field public static final int secondaryProgress = 16843064; // 0x1010138
+    field public static final int secondaryProgressTint = 16843881; // 0x1010469
+    field public static final int secondaryProgressTintMode = 16843882; // 0x101046a
     field public static final int seekBarStyle = 16842875; // 0x101007b
     field public static final int segmentedButtonStyle = 16843568; // 0x1010330
     field public static final int selectAllOnFocus = 16843102; // 0x101015e
@@ -1212,6 +1230,8 @@
     field public static final int thumb = 16843074; // 0x1010142
     field public static final int thumbOffset = 16843075; // 0x1010143
     field public static final int thumbTextPadding = 16843634; // 0x1010372
+    field public static final int thumbTint = 16843891; // 0x1010473
+    field public static final int thumbTintMode = 16843892; // 0x1010474
     field public static final int thumbnail = 16843429; // 0x10102a5
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int timeZone = 16843724; // 0x10103cc
@@ -1340,6 +1360,7 @@
     field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
     field public static final int windowTitleSize = 16842842; // 0x101005a
     field public static final int windowTitleStyle = 16842843; // 0x101005b
+    field public static final int windowTransitionBackgroundFadeDuration = 16843875; // 0x1010463
     field public static final int windowTranslucentNavigation = 16843760; // 0x10103f0
     field public static final int windowTranslucentStatus = 16843759; // 0x10103ef
     field public static final int writePermission = 16842760; // 0x1010008
@@ -1865,28 +1886,28 @@
     field public static final int TextAppearance_Large = 16973890; // 0x1030042
     field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
     field public static final int TextAppearance_Material = 16974350; // 0x103020e
-    field public static final int TextAppearance_Material_Body1 = 16974550; // 0x10302d6
-    field public static final int TextAppearance_Material_Body2 = 16974549; // 0x10302d5
-    field public static final int TextAppearance_Material_Button = 16974553; // 0x10302d9
-    field public static final int TextAppearance_Material_Caption = 16974551; // 0x10302d7
+    field public static final int TextAppearance_Material_Body1 = 16974552; // 0x10302d8
+    field public static final int TextAppearance_Material_Body2 = 16974551; // 0x10302d7
+    field public static final int TextAppearance_Material_Button = 16974555; // 0x10302db
+    field public static final int TextAppearance_Material_Caption = 16974553; // 0x10302d9
     field public static final int TextAppearance_Material_DialogWindowTitle = 16974351; // 0x103020f
-    field public static final int TextAppearance_Material_Display1 = 16974545; // 0x10302d1
-    field public static final int TextAppearance_Material_Display2 = 16974544; // 0x10302d0
-    field public static final int TextAppearance_Material_Display3 = 16974543; // 0x10302cf
-    field public static final int TextAppearance_Material_Display4 = 16974542; // 0x10302ce
-    field public static final int TextAppearance_Material_Headline = 16974546; // 0x10302d2
+    field public static final int TextAppearance_Material_Display1 = 16974547; // 0x10302d3
+    field public static final int TextAppearance_Material_Display2 = 16974546; // 0x10302d2
+    field public static final int TextAppearance_Material_Display3 = 16974545; // 0x10302d1
+    field public static final int TextAppearance_Material_Display4 = 16974544; // 0x10302d0
+    field public static final int TextAppearance_Material_Headline = 16974548; // 0x10302d4
     field public static final int TextAppearance_Material_Inverse = 16974352; // 0x1030210
     field public static final int TextAppearance_Material_Large = 16974353; // 0x1030211
     field public static final int TextAppearance_Material_Large_Inverse = 16974354; // 0x1030212
     field public static final int TextAppearance_Material_Medium = 16974355; // 0x1030213
     field public static final int TextAppearance_Material_Medium_Inverse = 16974356; // 0x1030214
-    field public static final int TextAppearance_Material_Menu = 16974552; // 0x10302d8
+    field public static final int TextAppearance_Material_Menu = 16974554; // 0x10302da
     field public static final int TextAppearance_Material_SearchResult_Subtitle = 16974357; // 0x1030215
     field public static final int TextAppearance_Material_SearchResult_Title = 16974358; // 0x1030216
     field public static final int TextAppearance_Material_Small = 16974359; // 0x1030217
     field public static final int TextAppearance_Material_Small_Inverse = 16974360; // 0x1030218
-    field public static final int TextAppearance_Material_Subhead = 16974548; // 0x10302d4
-    field public static final int TextAppearance_Material_Title = 16974547; // 0x10302d3
+    field public static final int TextAppearance_Material_Subhead = 16974550; // 0x10302d6
+    field public static final int TextAppearance_Material_Title = 16974549; // 0x10302d5
     field public static final int TextAppearance_Material_Widget = 16974362; // 0x103021a
     field public static final int TextAppearance_Material_Widget_ActionBar_Menu = 16974363; // 0x103021b
     field public static final int TextAppearance_Material_Widget_ActionBar_Subtitle = 16974364; // 0x103021c
@@ -1935,12 +1956,12 @@
     field public static final int TextAppearance_Widget_TextView_SpinnerItem = 16973906; // 0x1030052
     field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
     field public static final int Theme = 16973829; // 0x1030005
-    field public static final int ThemeOverlay = 16974414; // 0x103024e
-    field public static final int ThemeOverlay_Material = 16974415; // 0x103024f
-    field public static final int ThemeOverlay_Material_ActionBar = 16974416; // 0x1030250
-    field public static final int ThemeOverlay_Material_Dark = 16974418; // 0x1030252
-    field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974419; // 0x1030253
-    field public static final int ThemeOverlay_Material_Light = 16974417; // 0x1030251
+    field public static final int ThemeOverlay = 16974416; // 0x1030250
+    field public static final int ThemeOverlay_Material = 16974417; // 0x1030251
+    field public static final int ThemeOverlay_Material_ActionBar = 16974418; // 0x1030252
+    field public static final int ThemeOverlay_Material_Dark = 16974420; // 0x1030254
+    field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974421; // 0x1030255
+    field public static final int ThemeOverlay_Material_Light = 16974419; // 0x1030253
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -1970,6 +1991,7 @@
     field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974303; // 0x10301df
     field public static final int Theme_DeviceDefault_NoActionBar_TranslucentDecor = 16974307; // 0x10301e3
     field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
+    field public static final int Theme_DeviceDefault_Settings = 16974384; // 0x1030230
     field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
     field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
     field public static final int Theme_Dialog = 16973835; // 0x103000b
@@ -2007,36 +2029,37 @@
     field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
-    field public static final int Theme_Material = 16974384; // 0x1030230
-    field public static final int Theme_Material_Dialog = 16974385; // 0x1030231
-    field public static final int Theme_Material_DialogWhenLarge = 16974389; // 0x1030235
-    field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974390; // 0x1030236
-    field public static final int Theme_Material_Dialog_MinWidth = 16974386; // 0x1030232
-    field public static final int Theme_Material_Dialog_NoActionBar = 16974387; // 0x1030233
-    field public static final int Theme_Material_Dialog_NoActionBar_MinWidth = 16974388; // 0x1030234
-    field public static final int Theme_Material_InputMethod = 16974391; // 0x1030237
-    field public static final int Theme_Material_Light = 16974400; // 0x1030240
-    field public static final int Theme_Material_Light_DarkActionBar = 16974401; // 0x1030241
-    field public static final int Theme_Material_Light_Dialog = 16974402; // 0x1030242
-    field public static final int Theme_Material_Light_DialogWhenLarge = 16974406; // 0x1030246
-    field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974407; // 0x1030247
-    field public static final int Theme_Material_Light_Dialog_MinWidth = 16974403; // 0x1030243
-    field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974404; // 0x1030244
-    field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974405; // 0x1030245
-    field public static final int Theme_Material_Light_NoActionBar = 16974408; // 0x1030248
-    field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974409; // 0x1030249
-    field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974410; // 0x103024a
-    field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974411; // 0x103024b
-    field public static final int Theme_Material_Light_Panel = 16974412; // 0x103024c
-    field public static final int Theme_Material_Light_Voice = 16974413; // 0x103024d
-    field public static final int Theme_Material_NoActionBar = 16974392; // 0x1030238
-    field public static final int Theme_Material_NoActionBar_Fullscreen = 16974393; // 0x1030239
-    field public static final int Theme_Material_NoActionBar_Overscan = 16974394; // 0x103023a
-    field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974395; // 0x103023b
-    field public static final int Theme_Material_Panel = 16974396; // 0x103023c
-    field public static final int Theme_Material_Voice = 16974397; // 0x103023d
-    field public static final int Theme_Material_Wallpaper = 16974398; // 0x103023e
-    field public static final int Theme_Material_Wallpaper_NoTitleBar = 16974399; // 0x103023f
+    field public static final int Theme_Material = 16974385; // 0x1030231
+    field public static final int Theme_Material_Dialog = 16974386; // 0x1030232
+    field public static final int Theme_Material_DialogWhenLarge = 16974390; // 0x1030236
+    field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974391; // 0x1030237
+    field public static final int Theme_Material_Dialog_MinWidth = 16974387; // 0x1030233
+    field public static final int Theme_Material_Dialog_NoActionBar = 16974388; // 0x1030234
+    field public static final int Theme_Material_Dialog_NoActionBar_MinWidth = 16974389; // 0x1030235
+    field public static final int Theme_Material_InputMethod = 16974392; // 0x1030238
+    field public static final int Theme_Material_Light = 16974402; // 0x1030242
+    field public static final int Theme_Material_Light_DarkActionBar = 16974403; // 0x1030243
+    field public static final int Theme_Material_Light_Dialog = 16974404; // 0x1030244
+    field public static final int Theme_Material_Light_DialogWhenLarge = 16974408; // 0x1030248
+    field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974409; // 0x1030249
+    field public static final int Theme_Material_Light_Dialog_MinWidth = 16974405; // 0x1030245
+    field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974406; // 0x1030246
+    field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974407; // 0x1030247
+    field public static final int Theme_Material_Light_NoActionBar = 16974410; // 0x103024a
+    field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974411; // 0x103024b
+    field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974412; // 0x103024c
+    field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974413; // 0x103024d
+    field public static final int Theme_Material_Light_Panel = 16974414; // 0x103024e
+    field public static final int Theme_Material_Light_Voice = 16974415; // 0x103024f
+    field public static final int Theme_Material_NoActionBar = 16974393; // 0x1030239
+    field public static final int Theme_Material_NoActionBar_Fullscreen = 16974394; // 0x103023a
+    field public static final int Theme_Material_NoActionBar_Overscan = 16974395; // 0x103023b
+    field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974396; // 0x103023c
+    field public static final int Theme_Material_Panel = 16974397; // 0x103023d
+    field public static final int Theme_Material_Settings = 16974398; // 0x103023e
+    field public static final int Theme_Material_Voice = 16974399; // 0x103023f
+    field public static final int Theme_Material_Wallpaper = 16974400; // 0x1030240
+    field public static final int Theme_Material_Wallpaper_NoTitleBar = 16974401; // 0x1030241
     field public static final int Theme_NoDisplay = 16973909; // 0x1030055
     field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
@@ -2321,128 +2344,128 @@
     field public static final int Widget_ListView_DropDown = 16973872; // 0x1030030
     field public static final int Widget_ListView_Menu = 16973873; // 0x1030031
     field public static final int Widget_ListView_White = 16973871; // 0x103002f
-    field public static final int Widget_Material = 16974420; // 0x1030254
-    field public static final int Widget_Material_ActionBar = 16974421; // 0x1030255
-    field public static final int Widget_Material_ActionBar_Solid = 16974422; // 0x1030256
-    field public static final int Widget_Material_ActionBar_TabBar = 16974423; // 0x1030257
-    field public static final int Widget_Material_ActionBar_TabText = 16974424; // 0x1030258
-    field public static final int Widget_Material_ActionBar_TabView = 16974425; // 0x1030259
-    field public static final int Widget_Material_ActionButton = 16974426; // 0x103025a
-    field public static final int Widget_Material_ActionButton_CloseMode = 16974427; // 0x103025b
-    field public static final int Widget_Material_ActionButton_Overflow = 16974428; // 0x103025c
-    field public static final int Widget_Material_ActionMode = 16974429; // 0x103025d
-    field public static final int Widget_Material_AutoCompleteTextView = 16974430; // 0x103025e
-    field public static final int Widget_Material_Button = 16974431; // 0x103025f
-    field public static final int Widget_Material_ButtonBar = 16974437; // 0x1030265
-    field public static final int Widget_Material_ButtonBar_AlertDialog = 16974438; // 0x1030266
-    field public static final int Widget_Material_Button_Borderless = 16974432; // 0x1030260
-    field public static final int Widget_Material_Button_Borderless_Small = 16974433; // 0x1030261
-    field public static final int Widget_Material_Button_Inset = 16974434; // 0x1030262
-    field public static final int Widget_Material_Button_Small = 16974435; // 0x1030263
-    field public static final int Widget_Material_Button_Toggle = 16974436; // 0x1030264
-    field public static final int Widget_Material_CalendarView = 16974439; // 0x1030267
-    field public static final int Widget_Material_CheckedTextView = 16974440; // 0x1030268
-    field public static final int Widget_Material_CompoundButton_CheckBox = 16974441; // 0x1030269
-    field public static final int Widget_Material_CompoundButton_RadioButton = 16974442; // 0x103026a
-    field public static final int Widget_Material_CompoundButton_Star = 16974443; // 0x103026b
-    field public static final int Widget_Material_DatePicker = 16974444; // 0x103026c
-    field public static final int Widget_Material_DropDownItem = 16974445; // 0x103026d
-    field public static final int Widget_Material_DropDownItem_Spinner = 16974446; // 0x103026e
-    field public static final int Widget_Material_EditText = 16974447; // 0x103026f
-    field public static final int Widget_Material_ExpandableListView = 16974448; // 0x1030270
-    field public static final int Widget_Material_FastScroll = 16974449; // 0x1030271
-    field public static final int Widget_Material_GridView = 16974450; // 0x1030272
-    field public static final int Widget_Material_HorizontalScrollView = 16974451; // 0x1030273
-    field public static final int Widget_Material_ImageButton = 16974452; // 0x1030274
-    field public static final int Widget_Material_Light = 16974481; // 0x1030291
-    field public static final int Widget_Material_Light_ActionBar = 16974482; // 0x1030292
-    field public static final int Widget_Material_Light_ActionBar_Solid = 16974483; // 0x1030293
-    field public static final int Widget_Material_Light_ActionBar_TabBar = 16974484; // 0x1030294
-    field public static final int Widget_Material_Light_ActionBar_TabText = 16974485; // 0x1030295
-    field public static final int Widget_Material_Light_ActionBar_TabView = 16974486; // 0x1030296
-    field public static final int Widget_Material_Light_ActionButton = 16974487; // 0x1030297
-    field public static final int Widget_Material_Light_ActionButton_CloseMode = 16974488; // 0x1030298
-    field public static final int Widget_Material_Light_ActionButton_Overflow = 16974489; // 0x1030299
-    field public static final int Widget_Material_Light_ActionMode = 16974490; // 0x103029a
-    field public static final int Widget_Material_Light_AutoCompleteTextView = 16974491; // 0x103029b
-    field public static final int Widget_Material_Light_Button = 16974492; // 0x103029c
-    field public static final int Widget_Material_Light_ButtonBar = 16974498; // 0x10302a2
-    field public static final int Widget_Material_Light_ButtonBar_AlertDialog = 16974499; // 0x10302a3
-    field public static final int Widget_Material_Light_Button_Borderless = 16974493; // 0x103029d
-    field public static final int Widget_Material_Light_Button_Borderless_Small = 16974494; // 0x103029e
-    field public static final int Widget_Material_Light_Button_Inset = 16974495; // 0x103029f
-    field public static final int Widget_Material_Light_Button_Small = 16974496; // 0x10302a0
-    field public static final int Widget_Material_Light_Button_Toggle = 16974497; // 0x10302a1
-    field public static final int Widget_Material_Light_CalendarView = 16974500; // 0x10302a4
-    field public static final int Widget_Material_Light_CheckedTextView = 16974501; // 0x10302a5
-    field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974502; // 0x10302a6
-    field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974503; // 0x10302a7
-    field public static final int Widget_Material_Light_CompoundButton_Star = 16974504; // 0x10302a8
-    field public static final int Widget_Material_Light_DropDownItem = 16974505; // 0x10302a9
-    field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974506; // 0x10302aa
-    field public static final int Widget_Material_Light_EditText = 16974507; // 0x10302ab
-    field public static final int Widget_Material_Light_ExpandableListView = 16974508; // 0x10302ac
-    field public static final int Widget_Material_Light_FastScroll = 16974509; // 0x10302ad
-    field public static final int Widget_Material_Light_GridView = 16974510; // 0x10302ae
-    field public static final int Widget_Material_Light_HorizontalScrollView = 16974511; // 0x10302af
-    field public static final int Widget_Material_Light_ImageButton = 16974512; // 0x10302b0
-    field public static final int Widget_Material_Light_ListPopupWindow = 16974513; // 0x10302b1
-    field public static final int Widget_Material_Light_ListView = 16974514; // 0x10302b2
-    field public static final int Widget_Material_Light_ListView_DropDown = 16974515; // 0x10302b3
-    field public static final int Widget_Material_Light_MediaRouteButton = 16974516; // 0x10302b4
-    field public static final int Widget_Material_Light_PopupMenu = 16974517; // 0x10302b5
-    field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974518; // 0x10302b6
-    field public static final int Widget_Material_Light_PopupWindow = 16974519; // 0x10302b7
-    field public static final int Widget_Material_Light_ProgressBar = 16974520; // 0x10302b8
-    field public static final int Widget_Material_Light_ProgressBar_Horizontal = 16974521; // 0x10302b9
-    field public static final int Widget_Material_Light_ProgressBar_Inverse = 16974522; // 0x10302ba
-    field public static final int Widget_Material_Light_ProgressBar_Large = 16974523; // 0x10302bb
-    field public static final int Widget_Material_Light_ProgressBar_Large_Inverse = 16974524; // 0x10302bc
-    field public static final int Widget_Material_Light_ProgressBar_Small = 16974525; // 0x10302bd
-    field public static final int Widget_Material_Light_ProgressBar_Small_Inverse = 16974526; // 0x10302be
-    field public static final int Widget_Material_Light_ProgressBar_Small_Title = 16974527; // 0x10302bf
-    field public static final int Widget_Material_Light_RatingBar = 16974528; // 0x10302c0
-    field public static final int Widget_Material_Light_RatingBar_Indicator = 16974529; // 0x10302c1
-    field public static final int Widget_Material_Light_RatingBar_Small = 16974530; // 0x10302c2
-    field public static final int Widget_Material_Light_ScrollView = 16974531; // 0x10302c3
-    field public static final int Widget_Material_Light_SeekBar = 16974532; // 0x10302c4
-    field public static final int Widget_Material_Light_SegmentedButton = 16974533; // 0x10302c5
-    field public static final int Widget_Material_Light_Spinner = 16974535; // 0x10302c7
-    field public static final int Widget_Material_Light_StackView = 16974534; // 0x10302c6
-    field public static final int Widget_Material_Light_Tab = 16974536; // 0x10302c8
-    field public static final int Widget_Material_Light_TabWidget = 16974537; // 0x10302c9
-    field public static final int Widget_Material_Light_TextView = 16974538; // 0x10302ca
-    field public static final int Widget_Material_Light_TextView_SpinnerItem = 16974539; // 0x10302cb
-    field public static final int Widget_Material_Light_WebTextView = 16974540; // 0x10302cc
-    field public static final int Widget_Material_Light_WebView = 16974541; // 0x10302cd
-    field public static final int Widget_Material_ListPopupWindow = 16974453; // 0x1030275
-    field public static final int Widget_Material_ListView = 16974454; // 0x1030276
-    field public static final int Widget_Material_ListView_DropDown = 16974455; // 0x1030277
-    field public static final int Widget_Material_MediaRouteButton = 16974456; // 0x1030278
-    field public static final int Widget_Material_PopupMenu = 16974457; // 0x1030279
-    field public static final int Widget_Material_PopupMenu_Overflow = 16974458; // 0x103027a
-    field public static final int Widget_Material_PopupWindow = 16974459; // 0x103027b
-    field public static final int Widget_Material_ProgressBar = 16974460; // 0x103027c
-    field public static final int Widget_Material_ProgressBar_Horizontal = 16974461; // 0x103027d
-    field public static final int Widget_Material_ProgressBar_Large = 16974462; // 0x103027e
-    field public static final int Widget_Material_ProgressBar_Small = 16974463; // 0x103027f
-    field public static final int Widget_Material_ProgressBar_Small_Title = 16974464; // 0x1030280
-    field public static final int Widget_Material_RatingBar = 16974465; // 0x1030281
-    field public static final int Widget_Material_RatingBar_Indicator = 16974466; // 0x1030282
-    field public static final int Widget_Material_RatingBar_Small = 16974467; // 0x1030283
-    field public static final int Widget_Material_ScrollView = 16974468; // 0x1030284
-    field public static final int Widget_Material_SeekBar = 16974469; // 0x1030285
-    field public static final int Widget_Material_SegmentedButton = 16974470; // 0x1030286
-    field public static final int Widget_Material_Spinner = 16974472; // 0x1030288
-    field public static final int Widget_Material_StackView = 16974471; // 0x1030287
-    field public static final int Widget_Material_Tab = 16974473; // 0x1030289
-    field public static final int Widget_Material_TabWidget = 16974474; // 0x103028a
-    field public static final int Widget_Material_TextView = 16974475; // 0x103028b
-    field public static final int Widget_Material_TextView_SpinnerItem = 16974476; // 0x103028c
-    field public static final int Widget_Material_Toolbar = 16974477; // 0x103028d
-    field public static final int Widget_Material_Toolbar_Button_Navigation = 16974478; // 0x103028e
-    field public static final int Widget_Material_WebTextView = 16974479; // 0x103028f
-    field public static final int Widget_Material_WebView = 16974480; // 0x1030290
+    field public static final int Widget_Material = 16974422; // 0x1030256
+    field public static final int Widget_Material_ActionBar = 16974423; // 0x1030257
+    field public static final int Widget_Material_ActionBar_Solid = 16974424; // 0x1030258
+    field public static final int Widget_Material_ActionBar_TabBar = 16974425; // 0x1030259
+    field public static final int Widget_Material_ActionBar_TabText = 16974426; // 0x103025a
+    field public static final int Widget_Material_ActionBar_TabView = 16974427; // 0x103025b
+    field public static final int Widget_Material_ActionButton = 16974428; // 0x103025c
+    field public static final int Widget_Material_ActionButton_CloseMode = 16974429; // 0x103025d
+    field public static final int Widget_Material_ActionButton_Overflow = 16974430; // 0x103025e
+    field public static final int Widget_Material_ActionMode = 16974431; // 0x103025f
+    field public static final int Widget_Material_AutoCompleteTextView = 16974432; // 0x1030260
+    field public static final int Widget_Material_Button = 16974433; // 0x1030261
+    field public static final int Widget_Material_ButtonBar = 16974439; // 0x1030267
+    field public static final int Widget_Material_ButtonBar_AlertDialog = 16974440; // 0x1030268
+    field public static final int Widget_Material_Button_Borderless = 16974434; // 0x1030262
+    field public static final int Widget_Material_Button_Borderless_Small = 16974435; // 0x1030263
+    field public static final int Widget_Material_Button_Inset = 16974436; // 0x1030264
+    field public static final int Widget_Material_Button_Small = 16974437; // 0x1030265
+    field public static final int Widget_Material_Button_Toggle = 16974438; // 0x1030266
+    field public static final int Widget_Material_CalendarView = 16974441; // 0x1030269
+    field public static final int Widget_Material_CheckedTextView = 16974442; // 0x103026a
+    field public static final int Widget_Material_CompoundButton_CheckBox = 16974443; // 0x103026b
+    field public static final int Widget_Material_CompoundButton_RadioButton = 16974444; // 0x103026c
+    field public static final int Widget_Material_CompoundButton_Star = 16974445; // 0x103026d
+    field public static final int Widget_Material_DatePicker = 16974446; // 0x103026e
+    field public static final int Widget_Material_DropDownItem = 16974447; // 0x103026f
+    field public static final int Widget_Material_DropDownItem_Spinner = 16974448; // 0x1030270
+    field public static final int Widget_Material_EditText = 16974449; // 0x1030271
+    field public static final int Widget_Material_ExpandableListView = 16974450; // 0x1030272
+    field public static final int Widget_Material_FastScroll = 16974451; // 0x1030273
+    field public static final int Widget_Material_GridView = 16974452; // 0x1030274
+    field public static final int Widget_Material_HorizontalScrollView = 16974453; // 0x1030275
+    field public static final int Widget_Material_ImageButton = 16974454; // 0x1030276
+    field public static final int Widget_Material_Light = 16974483; // 0x1030293
+    field public static final int Widget_Material_Light_ActionBar = 16974484; // 0x1030294
+    field public static final int Widget_Material_Light_ActionBar_Solid = 16974485; // 0x1030295
+    field public static final int Widget_Material_Light_ActionBar_TabBar = 16974486; // 0x1030296
+    field public static final int Widget_Material_Light_ActionBar_TabText = 16974487; // 0x1030297
+    field public static final int Widget_Material_Light_ActionBar_TabView = 16974488; // 0x1030298
+    field public static final int Widget_Material_Light_ActionButton = 16974489; // 0x1030299
+    field public static final int Widget_Material_Light_ActionButton_CloseMode = 16974490; // 0x103029a
+    field public static final int Widget_Material_Light_ActionButton_Overflow = 16974491; // 0x103029b
+    field public static final int Widget_Material_Light_ActionMode = 16974492; // 0x103029c
+    field public static final int Widget_Material_Light_AutoCompleteTextView = 16974493; // 0x103029d
+    field public static final int Widget_Material_Light_Button = 16974494; // 0x103029e
+    field public static final int Widget_Material_Light_ButtonBar = 16974500; // 0x10302a4
+    field public static final int Widget_Material_Light_ButtonBar_AlertDialog = 16974501; // 0x10302a5
+    field public static final int Widget_Material_Light_Button_Borderless = 16974495; // 0x103029f
+    field public static final int Widget_Material_Light_Button_Borderless_Small = 16974496; // 0x10302a0
+    field public static final int Widget_Material_Light_Button_Inset = 16974497; // 0x10302a1
+    field public static final int Widget_Material_Light_Button_Small = 16974498; // 0x10302a2
+    field public static final int Widget_Material_Light_Button_Toggle = 16974499; // 0x10302a3
+    field public static final int Widget_Material_Light_CalendarView = 16974502; // 0x10302a6
+    field public static final int Widget_Material_Light_CheckedTextView = 16974503; // 0x10302a7
+    field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974504; // 0x10302a8
+    field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974505; // 0x10302a9
+    field public static final int Widget_Material_Light_CompoundButton_Star = 16974506; // 0x10302aa
+    field public static final int Widget_Material_Light_DropDownItem = 16974507; // 0x10302ab
+    field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974508; // 0x10302ac
+    field public static final int Widget_Material_Light_EditText = 16974509; // 0x10302ad
+    field public static final int Widget_Material_Light_ExpandableListView = 16974510; // 0x10302ae
+    field public static final int Widget_Material_Light_FastScroll = 16974511; // 0x10302af
+    field public static final int Widget_Material_Light_GridView = 16974512; // 0x10302b0
+    field public static final int Widget_Material_Light_HorizontalScrollView = 16974513; // 0x10302b1
+    field public static final int Widget_Material_Light_ImageButton = 16974514; // 0x10302b2
+    field public static final int Widget_Material_Light_ListPopupWindow = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_ListView = 16974516; // 0x10302b4
+    field public static final int Widget_Material_Light_ListView_DropDown = 16974517; // 0x10302b5
+    field public static final int Widget_Material_Light_MediaRouteButton = 16974518; // 0x10302b6
+    field public static final int Widget_Material_Light_PopupMenu = 16974519; // 0x10302b7
+    field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974520; // 0x10302b8
+    field public static final int Widget_Material_Light_PopupWindow = 16974521; // 0x10302b9
+    field public static final int Widget_Material_Light_ProgressBar = 16974522; // 0x10302ba
+    field public static final int Widget_Material_Light_ProgressBar_Horizontal = 16974523; // 0x10302bb
+    field public static final int Widget_Material_Light_ProgressBar_Inverse = 16974524; // 0x10302bc
+    field public static final int Widget_Material_Light_ProgressBar_Large = 16974525; // 0x10302bd
+    field public static final int Widget_Material_Light_ProgressBar_Large_Inverse = 16974526; // 0x10302be
+    field public static final int Widget_Material_Light_ProgressBar_Small = 16974527; // 0x10302bf
+    field public static final int Widget_Material_Light_ProgressBar_Small_Inverse = 16974528; // 0x10302c0
+    field public static final int Widget_Material_Light_ProgressBar_Small_Title = 16974529; // 0x10302c1
+    field public static final int Widget_Material_Light_RatingBar = 16974530; // 0x10302c2
+    field public static final int Widget_Material_Light_RatingBar_Indicator = 16974531; // 0x10302c3
+    field public static final int Widget_Material_Light_RatingBar_Small = 16974532; // 0x10302c4
+    field public static final int Widget_Material_Light_ScrollView = 16974533; // 0x10302c5
+    field public static final int Widget_Material_Light_SeekBar = 16974534; // 0x10302c6
+    field public static final int Widget_Material_Light_SegmentedButton = 16974535; // 0x10302c7
+    field public static final int Widget_Material_Light_Spinner = 16974537; // 0x10302c9
+    field public static final int Widget_Material_Light_StackView = 16974536; // 0x10302c8
+    field public static final int Widget_Material_Light_Tab = 16974538; // 0x10302ca
+    field public static final int Widget_Material_Light_TabWidget = 16974539; // 0x10302cb
+    field public static final int Widget_Material_Light_TextView = 16974540; // 0x10302cc
+    field public static final int Widget_Material_Light_TextView_SpinnerItem = 16974541; // 0x10302cd
+    field public static final int Widget_Material_Light_WebTextView = 16974542; // 0x10302ce
+    field public static final int Widget_Material_Light_WebView = 16974543; // 0x10302cf
+    field public static final int Widget_Material_ListPopupWindow = 16974455; // 0x1030277
+    field public static final int Widget_Material_ListView = 16974456; // 0x1030278
+    field public static final int Widget_Material_ListView_DropDown = 16974457; // 0x1030279
+    field public static final int Widget_Material_MediaRouteButton = 16974458; // 0x103027a
+    field public static final int Widget_Material_PopupMenu = 16974459; // 0x103027b
+    field public static final int Widget_Material_PopupMenu_Overflow = 16974460; // 0x103027c
+    field public static final int Widget_Material_PopupWindow = 16974461; // 0x103027d
+    field public static final int Widget_Material_ProgressBar = 16974462; // 0x103027e
+    field public static final int Widget_Material_ProgressBar_Horizontal = 16974463; // 0x103027f
+    field public static final int Widget_Material_ProgressBar_Large = 16974464; // 0x1030280
+    field public static final int Widget_Material_ProgressBar_Small = 16974465; // 0x1030281
+    field public static final int Widget_Material_ProgressBar_Small_Title = 16974466; // 0x1030282
+    field public static final int Widget_Material_RatingBar = 16974467; // 0x1030283
+    field public static final int Widget_Material_RatingBar_Indicator = 16974468; // 0x1030284
+    field public static final int Widget_Material_RatingBar_Small = 16974469; // 0x1030285
+    field public static final int Widget_Material_ScrollView = 16974470; // 0x1030286
+    field public static final int Widget_Material_SeekBar = 16974471; // 0x1030287
+    field public static final int Widget_Material_SegmentedButton = 16974472; // 0x1030288
+    field public static final int Widget_Material_Spinner = 16974474; // 0x103028a
+    field public static final int Widget_Material_StackView = 16974473; // 0x1030289
+    field public static final int Widget_Material_Tab = 16974475; // 0x103028b
+    field public static final int Widget_Material_TabWidget = 16974476; // 0x103028c
+    field public static final int Widget_Material_TextView = 16974477; // 0x103028d
+    field public static final int Widget_Material_TextView_SpinnerItem = 16974478; // 0x103028e
+    field public static final int Widget_Material_Toolbar = 16974479; // 0x103028f
+    field public static final int Widget_Material_Toolbar_Button_Navigation = 16974480; // 0x1030290
+    field public static final int Widget_Material_WebTextView = 16974481; // 0x1030291
+    field public static final int Widget_Material_WebView = 16974482; // 0x1030292
     field public static final int Widget_PopupMenu = 16973958; // 0x1030086
     field public static final int Widget_PopupWindow = 16973878; // 0x1030036
     field public static final int Widget_ProgressBar = 16973852; // 0x103001c
@@ -3342,6 +3365,7 @@
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
     method public void overridePendingTransition(int, int);
+    method public void postponeEnterTransition();
     method public void recreate();
     method public void registerForContextMenu(android.view.View);
     method public final deprecated void removeDialog(int);
@@ -3397,6 +3421,7 @@
     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 startPostponedEnterTransition();
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
     method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
@@ -4194,6 +4219,9 @@
     method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
     method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
     method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+    method public abstract android.app.FragmentTransaction setCustomTransition(int, int);
+    method public abstract android.app.FragmentTransaction setSharedElement(android.view.View, java.lang.String);
+    method public abstract android.app.FragmentTransaction setSharedElements(android.util.Pair<android.view.View, java.lang.String>...);
     method public abstract android.app.FragmentTransaction setTransition(int);
     method public abstract android.app.FragmentTransaction setTransitionStyle(int);
     method public abstract android.app.FragmentTransaction show(android.app.Fragment);
@@ -5191,6 +5219,7 @@
     method public void clearDeviceOwnerApp();
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+    method public android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
     method public android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
     method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
@@ -5372,23 +5401,9 @@
 
 }
 
-package android.app.maintenance {
+package android.app.job {
 
-  public abstract class IdleService extends android.app.Service {
-    ctor public IdleService();
-    method public final void finishIdle();
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract boolean onIdleStart();
-    method public abstract void onIdleStop();
-    field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_IDLE_SERVICE";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.idle.IdleService";
-  }
-
-}
-
-package android.app.task {
-
-  public class Task implements android.os.Parcelable {
+  public class JobInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getBackoffPolicy();
     method public android.os.PersistableBundle getExtras();
@@ -5406,55 +5421,55 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
-  public static abstract interface Task.BackoffPolicy {
+  public static abstract interface JobInfo.BackoffPolicy {
     field public static final int EXPONENTIAL = 1; // 0x1
     field public static final int LINEAR = 0; // 0x0
   }
 
-  public static final class Task.Builder {
-    ctor public Task.Builder(int, android.content.ComponentName);
-    method public android.app.task.Task build();
-    method public android.app.task.Task.Builder setBackoffCriteria(long, int);
-    method public android.app.task.Task.Builder setExtras(android.os.PersistableBundle);
-    method public android.app.task.Task.Builder setMinimumLatency(long);
-    method public android.app.task.Task.Builder setOverrideDeadline(long);
-    method public android.app.task.Task.Builder setPeriodic(long);
-    method public android.app.task.Task.Builder setRequiredNetworkCapabilities(int);
-    method public android.app.task.Task.Builder setRequiresCharging(boolean);
-    method public android.app.task.Task.Builder setRequiresDeviceIdle(boolean);
+  public static final class JobInfo.Builder {
+    ctor public JobInfo.Builder(int, android.content.ComponentName);
+    method public android.app.job.JobInfo build();
+    method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
+    method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.app.job.JobInfo.Builder setMinimumLatency(long);
+    method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
+    method public android.app.job.JobInfo.Builder setPeriodic(long);
+    method public android.app.job.JobInfo.Builder setRequiredNetworkCapabilities(int);
+    method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
+    method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
   }
 
-  public static abstract interface Task.NetworkType {
+  public static abstract interface JobInfo.NetworkType {
     field public static final int ANY = 1; // 0x1
     field public static final int NONE = 0; // 0x0
     field public static final int UNMETERED = 2; // 0x2
   }
 
-  public abstract class TaskManager {
-    ctor public TaskManager();
-    method public abstract void cancel(int);
-    method public abstract void cancelAll();
-    method public abstract java.util.List<android.app.task.Task> getAllPendingTasks();
-    method public abstract int schedule(android.app.task.Task);
-    field public static final int RESULT_FAILURE = 0; // 0x0
-    field public static final int RESULT_SUCCESS = 1; // 0x1
-  }
-
-  public class TaskParams implements android.os.Parcelable {
+  public class JobParameters implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.PersistableBundle getExtras();
-    method public int getTaskId();
+    method public int getJobId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
-  public abstract class TaskService extends android.app.Service {
-    ctor public TaskService();
+  public abstract class JobScheduler {
+    ctor public JobScheduler();
+    method public abstract void cancel(int);
+    method public abstract void cancelAll();
+    method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+    method public abstract int schedule(android.app.job.JobInfo);
+    field public static final int RESULT_FAILURE = 0; // 0x0
+    field public static final int RESULT_SUCCESS = 1; // 0x1
+  }
+
+  public abstract class JobService extends android.app.Service {
+    ctor public JobService();
+    method public final void jobFinished(android.app.job.JobParameters, boolean);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract boolean onStartTask(android.app.task.TaskParams);
-    method public abstract boolean onStopTask(android.app.task.TaskParams);
-    method public final void taskFinished(android.app.task.TaskParams, boolean);
-    field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
+    method public abstract boolean onStartJob(android.app.job.JobParameters);
+    method public abstract boolean onStopJob(android.app.job.JobParameters);
+    field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
   }
 
 }
@@ -7023,6 +7038,7 @@
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
+    field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
     field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
     field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
     field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
@@ -7044,7 +7060,7 @@
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
-    field public static final java.lang.String TASK_SERVICE = "task";
+    field public static final java.lang.String TELECOMM_SERVICE = "telecomm";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
@@ -8251,11 +8267,11 @@
   }
 
   public static abstract interface LauncherApps.OnAppsChangedListener {
-    method public abstract void onPackageAdded(java.lang.String, android.os.UserHandle);
-    method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
-    method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
-    method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
-    method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
+    method public abstract void onPackageAdded(android.os.UserHandle, java.lang.String);
+    method public abstract void onPackageChanged(android.os.UserHandle, java.lang.String);
+    method public abstract void onPackageRemoved(android.os.UserHandle, java.lang.String);
+    method public abstract void onPackagesAvailable(android.os.UserHandle, java.lang.String[], boolean);
+    method public abstract void onPackagesUnavailable(android.os.UserHandle, java.lang.String[], boolean);
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -10211,6 +10227,7 @@
     method public void concat(android.graphics.Matrix);
     method public void drawARGB(int, int, int, int);
     method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
+    method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
     method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
@@ -10225,6 +10242,7 @@
     method public void drawLines(float[], int, int, android.graphics.Paint);
     method public void drawLines(float[], android.graphics.Paint);
     method public void drawOval(android.graphics.RectF, android.graphics.Paint);
+    method public void drawOval(float, float, float, float, android.graphics.Paint);
     method public void drawPaint(android.graphics.Paint);
     method public void drawPath(android.graphics.Path, android.graphics.Paint);
     method public void drawPicture(android.graphics.Picture);
@@ -10734,6 +10752,7 @@
     ctor public Path();
     ctor public Path(android.graphics.Path);
     method public void addArc(android.graphics.RectF, float, float);
+    method public void addArc(float, float, float, float, float, float);
     method public void addCircle(float, float, float, android.graphics.Path.Direction);
     method public void addOval(android.graphics.RectF, android.graphics.Path.Direction);
     method public void addOval(float, float, float, float, android.graphics.Path.Direction);
@@ -10743,9 +10762,12 @@
     method public void addRect(android.graphics.RectF, android.graphics.Path.Direction);
     method public void addRect(float, float, float, float, android.graphics.Path.Direction);
     method public void addRoundRect(android.graphics.RectF, float, float, android.graphics.Path.Direction);
+    method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
     method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
+    method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
     method public void arcTo(android.graphics.RectF, float, float, boolean);
     method public void arcTo(android.graphics.RectF, float, float);
+    method public void arcTo(float, float, float, float, float, float, boolean);
     method public void close();
     method public void computeBounds(android.graphics.RectF, boolean);
     method public void cubicTo(float, float, float, float, float, float);
@@ -11969,14 +11991,18 @@
     method public int getMinDelay();
     method public java.lang.String getName();
     method public float getPower();
+    method public int getReportingMode();
     method public float getResolution();
     method public java.lang.String getStringType();
     method public int getType();
     method public java.lang.String getVendor();
     method public int getVersion();
     method public boolean isWakeUpSensor();
+    field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
+    field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
+    field public static final int REPORTING_MODE_ON_CHANGE = 1; // 0x1
+    field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
     field public static final java.lang.String SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR = "android.sensor.non_wake_up_proximity_sensor";
-    field public static final java.lang.String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR = "android.sensor.wake_up_tilt_detector";
     field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
     field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
     field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
@@ -12057,7 +12083,6 @@
     field public static final int TYPE_WAKE_UP_ROTATION_VECTOR = 31; // 0x1f
     field public static final int TYPE_WAKE_UP_STEP_COUNTER = 38; // 0x26
     field public static final int TYPE_WAKE_UP_STEP_DETECTOR = 37; // 0x25
-    field public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41; // 0x29
   }
 
   public class SensorEvent {
@@ -12278,6 +12303,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PHYSICAL_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_SENSITIVITY_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_CALIBRATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION;
@@ -12486,6 +12512,8 @@
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4; // 0x4
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB = 0; // 0x0
+    field public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED = 1; // 0x1
+    field public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED = 0; // 0x0
     field public static final int SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10; // 0xa
     field public static final int SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14; // 0xe
     field public static final int SENSOR_REFERENCE_ILLUMINANT1_D50 = 23; // 0x17
@@ -12664,6 +12692,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT;
+    field public static final android.hardware.camera2.CaptureResult.Key SENSOR_ROLLING_SHUTTER_SKEW;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA;
     field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_MODE;
@@ -13693,6 +13722,7 @@
     method public void adjustStreamVolume(int, int, int);
     method public void adjustSuggestedStreamVolume(int, int, int);
     method public void adjustVolume(int, int);
+    method public int allocateAudioSessionId();
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -13753,6 +13783,7 @@
     field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
     field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
     field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
+    field public static final int ERROR = -1; // 0xffffffff
     field public static final java.lang.String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
     field public static final java.lang.String EXTRA_SCO_AUDIO_PREVIOUS_STATE = "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
     field public static final java.lang.String EXTRA_SCO_AUDIO_STATE = "android.media.extra.SCO_AUDIO_STATE";
@@ -13932,6 +13963,7 @@
     method public static boolean hasProfile(int);
     method public static boolean hasProfile(int, int);
     field public static final int QUALITY_1080P = 6; // 0x6
+    field public static final int QUALITY_2160P = 8; // 0x8
     field public static final int QUALITY_480P = 4; // 0x4
     field public static final int QUALITY_720P = 5; // 0x5
     field public static final int QUALITY_CIF = 3; // 0x3
@@ -13940,6 +13972,7 @@
     field public static final int QUALITY_QCIF = 2; // 0x2
     field public static final int QUALITY_QVGA = 7; // 0x7
     field public static final int QUALITY_TIME_LAPSE_1080P = 1006; // 0x3ee
+    field public static final int QUALITY_TIME_LAPSE_2160P = 1008; // 0x3f0
     field public static final int QUALITY_TIME_LAPSE_480P = 1004; // 0x3ec
     field public static final int QUALITY_TIME_LAPSE_720P = 1005; // 0x3ed
     field public static final int QUALITY_TIME_LAPSE_CIF = 1003; // 0x3eb
@@ -15783,7 +15816,9 @@
     method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName);
     method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName, boolean);
     method public static final android.net.Uri buildProgramUri(long);
+    method public static final android.net.Uri buildProgramsUriForChannel(long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+    method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
@@ -15830,8 +15865,11 @@
     field public static final int TYPE_ISDB_S = 262656; // 0x40200
     field public static final int TYPE_ISDB_T = 262144; // 0x40000
     field public static final int TYPE_ISDB_TB = 262400; // 0x40100
+    field public static final int TYPE_NTSC = 1; // 0x1
     field public static final int TYPE_OTHER = 0; // 0x0
+    field public static final int TYPE_PAL = 2; // 0x2
     field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
+    field public static final int TYPE_SECAM = 3; // 0x3
     field public static final int TYPE_S_DMB = 393472; // 0x60100
     field public static final int TYPE_T_DMB = 393216; // 0x60000
   }
@@ -15882,6 +15920,7 @@
     method public android.content.Intent getIntentForSetupActivity();
     method public android.content.pm.ServiceInfo getServiceInfo();
     method public int getType();
+    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String EXTRA_SERVICE_NAME = "serviceName";
@@ -16092,28 +16131,25 @@
     method public deprecated int getNetworkPreference();
     method public static android.net.Network getProcessDefaultNetwork();
     method public boolean isActiveNetworkMetered();
-    method public boolean isNetworkActive();
+    method public boolean isDefaultNetworkActive();
     method public static boolean isNetworkTypeValid(int);
-    method public android.net.NetworkRequest listenForNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
-    method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public void releaseNetworkRequest(android.net.NetworkRequest);
+    method public void registerDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+    method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void reportBadNetwork(android.net.Network);
-    method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
-    method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.app.PendingIntent);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
     method public static boolean setProcessDefaultNetwork(android.net.Network);
     method public deprecated int startUsingNetworkFeature(int, java.lang.String);
     method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
-    method public void unregisterNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+    method public void unregisterDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+    method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
-    field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
-    field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES = "networkRequestNetworkCapabilities";
     field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
@@ -16130,14 +16166,13 @@
     field public static final int TYPE_WIMAX = 6; // 0x6
   }
 
-  public static class ConnectivityManager.NetworkCallbackListener {
-    ctor public ConnectivityManager.NetworkCallbackListener();
-    method public void onAvailable(android.net.NetworkRequest, android.net.Network);
-    method public void onLinkPropertiesChanged(android.net.NetworkRequest, android.net.Network, android.net.LinkProperties);
-    method public void onLosing(android.net.NetworkRequest, android.net.Network, int);
-    method public void onLost(android.net.NetworkRequest, android.net.Network);
-    method public void onNetworkCapabilitiesChanged(android.net.NetworkRequest, android.net.Network, android.net.NetworkCapabilities);
-    method public void onReleased(android.net.NetworkRequest);
+  public static class ConnectivityManager.NetworkCallback {
+    ctor public ConnectivityManager.NetworkCallback();
+    method public void onAvailable(android.net.Network);
+    method public void onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities);
+    method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
+    method public void onLosing(android.net.Network, int);
+    method public void onLost(android.net.Network);
   }
 
   public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -16164,12 +16199,13 @@
     field public int serverAddress;
   }
 
-  public class IpPrefix implements android.os.Parcelable {
+  public final class IpPrefix implements android.os.Parcelable {
     method public int describeContents();
     method public java.net.InetAddress getAddress();
     method public int getPrefixLength();
     method public byte[] getRawAddress();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
   }
 
   public class LinkAddress implements android.os.Parcelable {
@@ -16181,7 +16217,7 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public class LinkProperties implements android.os.Parcelable {
+  public final class LinkProperties implements android.os.Parcelable {
     method public int describeContents();
     method public java.util.List<java.net.InetAddress> getDnsServers();
     method public java.lang.String getDomains();
@@ -16271,21 +16307,12 @@
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
-    ctor public NetworkCapabilities();
     ctor public NetworkCapabilities(android.net.NetworkCapabilities);
-    method public void addNetworkCapability(int);
-    method public void addTransportType(int);
     method public int describeContents();
     method public int getLinkDownstreamBandwidthKbps();
     method public int getLinkUpstreamBandwidthKbps();
-    method public java.util.Collection<java.lang.Integer> getNetworkCapabilities();
-    method public java.util.Collection<java.lang.Integer> getTransportTypes();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
-    method public void removeNetworkCapability(int);
-    method public void removeTransportType(int);
-    method public void setLinkDownstreamBandwidthKbps(int);
-    method public void setLinkUpstreamBandwidthKbps(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int NET_CAPABILITY_CBS = 5; // 0x5
@@ -16359,7 +16386,27 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public final android.net.NetworkCapabilities networkCapabilities;
+  }
+
+  public static class NetworkRequest.Builder {
+    ctor public NetworkRequest.Builder();
+    method public android.net.NetworkRequest.Builder addCapability(int);
+    method public android.net.NetworkRequest.Builder addTransportType(int);
+    method public android.net.NetworkRequest build();
+    method public android.net.NetworkRequest.Builder removeCapability(int);
+    method public android.net.NetworkRequest.Builder removeTransportType(int);
+  }
+
+  public abstract interface PSKKeyManager {
+    method public abstract java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
+    method public abstract java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
+    method public abstract java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
+    method public abstract java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
+    method public abstract javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
+    method public abstract javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
+    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
   }
 
   public class ParseException extends java.lang.RuntimeException {
@@ -16388,7 +16435,7 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public class RouteInfo implements android.os.Parcelable {
+  public final class RouteInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.IpPrefix getDestination();
     method public java.net.InetAddress getGateway();
@@ -16396,6 +16443,7 @@
     method public boolean isDefaultRoute();
     method public boolean matches(java.net.InetAddress);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
   }
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
@@ -25984,29 +26032,61 @@
 package android.service.fingerprint {
 
   public class FingerprintManager {
-    ctor public FingerprintManager(android.content.Context);
+    ctor public FingerprintManager(android.content.Context, android.service.fingerprint.IFingerprintService);
     method public void enroll(long);
+    method public void enrollCancel();
     method public boolean enrolledAndEnabled();
     method public void remove(int);
     method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
     method public void stopListening();
+    field public static final int FINGERPRINT_ACQUIRED = 1; // 0x1
+    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4; // 0x4
+    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16; // 0x10
+    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8; // 0x8
     field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
-    field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
     field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
     field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
     field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
     field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
-    field public static final int FINGERPRINT_SCANNED = 1; // 0x1
-    field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+    field public static final int FINGERPRINT_PROCESSED = 2; // 0x2
+    field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; // 0x3
     field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
   }
 
   public class FingerprintManagerReceiver {
     ctor public FingerprintManagerReceiver();
+    method public void onAcquired(int);
     method public void onEnrollResult(int, int);
     method public void onError(int);
+    method public void onProcessed(int);
     method public void onRemoved(int);
-    method public void onScanned(int, int);
+  }
+
+  public class FingerprintUtils {
+    ctor public FingerprintUtils();
+    method public static void addFingerprintIdForUser(int, android.content.ContentResolver, int);
+    method public static int[] getFingerprintIdsForUser(android.content.ContentResolver, int);
+    method public static boolean removeFingerprintIdForUser(int, android.content.ContentResolver, int);
+  }
+
+  public abstract interface IFingerprintService implements android.os.IInterface {
+    method public abstract void enroll(android.os.IBinder, long, int) throws android.os.RemoteException;
+    method public abstract void enrollCancel(android.os.IBinder, int) throws android.os.RemoteException;
+    method public abstract void remove(android.os.IBinder, int, int) throws android.os.RemoteException;
+    method public abstract void startListening(android.os.IBinder, android.service.fingerprint.IFingerprintServiceReceiver, int) throws android.os.RemoteException;
+    method public abstract void stopListening(android.os.IBinder, int) throws android.os.RemoteException;
+  }
+
+  public abstract interface IFingerprintServiceReceiver implements android.os.IInterface {
+    method public abstract void onAcquired(int) throws android.os.RemoteException;
+    method public abstract void onEnrollResult(int, int) throws android.os.RemoteException;
+    method public abstract void onError(int) throws android.os.RemoteException;
+    method public abstract void onProcessed(int) throws android.os.RemoteException;
+    method public abstract void onRemoved(int) throws android.os.RemoteException;
   }
 
 }
@@ -26020,21 +26100,28 @@
     method public final void cancelNotification(java.lang.String);
     method public final void cancelNotifications(java.lang.String[]);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
-    method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking();
+    method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onListenerConnected();
-    method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
-    method public void onNotificationRankingUpdate();
-    method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
+    method public void onNotificationPosted(android.service.notification.StatusBarNotification);
+    method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+    method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
+    method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
+    method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
   }
 
-  public static class NotificationListenerService.Ranking implements android.os.Parcelable {
+  public static class NotificationListenerService.Ranking {
+    method public java.lang.String getKey();
+    method public int getRank();
+    method public boolean isAmbient();
+    method public boolean isInterceptedByDoNotDisturb();
+  }
+
+  public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.String[] getOrderedKeys();
-    method public int getRank(java.lang.String);
-    method public boolean isAmbient(java.lang.String);
-    method public boolean isInterceptedByDoNotDisturb(java.lang.String);
+    method public android.service.notification.NotificationListenerService.Ranking getRanking(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -26511,6 +26598,7 @@
   }
 
   public static final class TextToSpeechClient.EngineStatus {
+    method public java.util.Locale getDefaultLocale();
     method public java.lang.String getEnginePackage();
     method public java.util.List<android.speech.tts.VoiceInfo> getVoices();
   }
@@ -27347,8 +27435,8 @@
     field public final int supportedRouteMask;
   }
 
-  public class CallCapabilities {
-    ctor public CallCapabilities();
+  public final class CallCapabilities {
+    method public static java.lang.String toString(int);
     field public static final int ADD_CALL = 16; // 0x10
     field public static final int ALL = 511; // 0x1ff
     field public static final int CONNECTION_HANDOFF = 256; // 0x100
@@ -27407,6 +27495,7 @@
   }
 
   public final class CallServiceAdapter {
+    method public void addConferenceCall(java.lang.String);
     method public void handleFailedOutgoingCall(android.telecomm.ConnectionRequest, int, java.lang.String);
     method public void handleSuccessfulOutgoingCall(java.lang.String);
     method public void handoffCall(java.lang.String);
@@ -27481,16 +27570,23 @@
 
   public abstract class Connection {
     ctor protected Connection();
+    method public final void conference();
     method public final android.telecomm.CallAudioState getCallAudioState();
+    method public java.util.List<android.telecomm.Connection> getChildConnections();
     method public final android.net.Uri getHandle();
+    method public android.telecomm.Connection getParentConnection();
+    method public boolean isConferenceConnection();
     method public boolean isRequestingRingback();
     method protected void onAbort();
     method protected void onAnswer();
+    method protected void onChildrenChanged(java.util.List<android.telecomm.Connection>);
+    method protected void onConference();
     method protected void onDisconnect();
     method protected void onHold();
     method protected void onPlayDtmfTone(char);
     method protected void onPostDialContinue(boolean);
     method protected void onReject();
+    method protected void onSeparate();
     method protected void onSetAudioState(android.telecomm.CallAudioState);
     method protected void onSetSignal(android.os.Bundle);
     method protected void onSetState(int);
@@ -27498,10 +27594,13 @@
     method protected void onUnhold();
     method protected void setActive();
     method public void setAudioState(android.telecomm.CallAudioState);
+    method protected void setDestroyed();
     method protected void setDialing();
     method protected void setDisconnected(int, java.lang.String);
     method protected void setHandle(android.net.Uri);
+    method protected void setIsConferenceCapable(boolean);
     method protected void setOnHold();
+    method public void setParentConnection(android.telecomm.Connection);
     method protected void setRequestingRingback(boolean);
     method protected void setRinging();
     method public static java.lang.String stateToString(int);
@@ -27509,9 +27608,11 @@
 
   public static abstract interface Connection.Listener {
     method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+    method public abstract void onConferenceCapableChanged(android.telecomm.Connection, boolean);
     method public abstract void onDestroyed(android.telecomm.Connection);
     method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
     method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+    method public abstract void onParentConnectionChanged(android.telecomm.Connection, android.telecomm.Connection);
     method public abstract void onRequestingRingback(android.telecomm.Connection, boolean);
     method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
     method public abstract void onStateChanged(android.telecomm.Connection, int);
@@ -27520,9 +27621,11 @@
   public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
     ctor public Connection.ListenerBase();
     method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+    method public void onConferenceCapableChanged(android.telecomm.Connection, boolean);
     method public void onDestroyed(android.telecomm.Connection);
     method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
     method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+    method public void onParentConnectionChanged(android.telecomm.Connection, android.telecomm.Connection);
     method public void onRequestingRingback(android.telecomm.Connection, boolean);
     method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
     method public void onStateChanged(android.telecomm.Connection, int);
@@ -27554,9 +27657,13 @@
     method public final void answer(java.lang.String);
     method public final void call(android.telecomm.CallInfo);
     method public final void disconnect(java.lang.String);
+    method public java.util.Collection<android.telecomm.Connection> getAllConnections();
     method public final void hold(java.lang.String);
     method public final void isCompatibleWith(android.telecomm.CallInfo);
     method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+    method public void onConnectionAdded(android.telecomm.Connection);
+    method public void onConnectionRemoved(android.telecomm.Connection);
+    method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
     method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
     method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
     method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
@@ -27587,7 +27694,7 @@
     method public void mute(boolean);
     method public void playDtmfTone(java.lang.String, char);
     method public void postDialContinue(java.lang.String, boolean);
-    method public void rejectCall(java.lang.String);
+    method public void rejectCall(java.lang.String, boolean, java.lang.String);
     method public void setAudioRoute(int);
     method public void stopDtmfTone(java.lang.String);
     method public void unholdCall(java.lang.String);
@@ -27595,6 +27702,7 @@
 
   public final class InCallCall implements android.os.Parcelable {
     method public int describeContents();
+    method public java.util.List<java.lang.String> getCannedSmsResponses();
     method public int getCapabilities();
     method public long getConnectTimeMillis();
     method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
@@ -27639,6 +27747,7 @@
     field public static final java.lang.String ACTION_CALL_SERVICE;
     field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
     field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
+    field public static final java.lang.String ACTION_CHANGE_DEFAULT_PHONE = "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE";
     field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
@@ -27646,6 +27755,11 @@
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
     field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
     field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+  }
+
+  public class TelecommManager {
   }
 
 }
@@ -32446,6 +32560,8 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.graphics.drawable.Drawable getBackground();
+    method public android.content.res.ColorStateList getBackgroundTint();
+    method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
     method public int getBaseline();
     method public final int getBottom();
     method protected float getBottomFadingEdgeStrength();
@@ -32723,6 +32839,8 @@
     method public void setBackgroundColor(int);
     method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setBackgroundResource(int);
+    method public void setBackgroundTint(android.content.res.ColorStateList);
+    method public void setBackgroundTintMode(android.graphics.PorterDuff.Mode);
     method public final void setBottom(int);
     method public void setCameraDistance(float);
     method public void setClickable(boolean);
@@ -33048,7 +33166,7 @@
     method public abstract boolean onTouch(android.view.View, android.view.MotionEvent);
   }
 
-  public class ViewAnimationUtils {
+  public final class ViewAnimationUtils {
     method public static final android.animation.ValueAnimator createCircularReveal(android.view.View, int, int, float, float);
   }
 
@@ -33513,6 +33631,7 @@
     method public android.transition.Transition getSharedElementEnterTransition();
     method public android.transition.Transition getSharedElementExitTransition();
     method public abstract int getStatusBarColor();
+    method public long getTransitionBackgroundFadeDuration();
     method public android.transition.TransitionManager getTransitionManager();
     method public abstract int getVolumeControlStream();
     method public android.view.WindowManager getWindowManager();
@@ -33571,6 +33690,7 @@
     method public abstract void setStatusBarColor(int);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
+    method public void setTransitionBackgroundFadeDuration(long);
     method public void setTransitionManager(android.transition.TransitionManager);
     method public void setType(int);
     method public void setUiOptions(int);
@@ -34585,15 +34705,15 @@
     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);
+  public static final class CursorAnchorInfo.Builder {
+    ctor public CursorAnchorInfo.Builder();
+    method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterRect(int, float, float, float, float);
     method public android.view.inputmethod.CursorAnchorInfo build();
     method public void reset();
-    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setComposingText(int, java.lang.CharSequence);
-    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);
+    method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, java.lang.CharSequence);
+    method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float);
+    method public android.view.inputmethod.CursorAnchorInfo.Builder setMatrix(android.graphics.Matrix);
+    method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
   }
 
   public class EditorInfo implements android.text.InputType android.os.Parcelable {
@@ -34968,7 +35088,8 @@
 
 package android.webkit {
 
-  public abstract interface ClientCertRequest {
+  public abstract class ClientCertRequest {
+    ctor public ClientCertRequest();
     method public abstract void cancel();
     method public abstract java.lang.String getHost();
     method public abstract java.lang.String[] getKeyTypes();
@@ -35002,12 +35123,15 @@
     method public java.lang.String getCookie(java.lang.String);
     method public static synchronized android.webkit.CookieManager getInstance();
     method public synchronized boolean hasCookies();
-    method public void removeAllCookie();
-    method public void removeExpiredCookie();
-    method public void removeSessionCookie();
+    method public deprecated void removeAllCookie();
+    method public void removeAllCookies(android.webkit.ValueCallback<java.lang.Boolean>);
+    method public deprecated void removeExpiredCookie();
+    method public deprecated void removeSessionCookie();
+    method public void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>);
     method public synchronized void setAcceptCookie(boolean);
     method public static void setAcceptFileSchemeCookies(boolean);
     method public void setCookie(java.lang.String, java.lang.String);
+    method public void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
   }
 
   public final class CookieSyncManager extends android.webkit.WebSyncManager {
@@ -35149,12 +35273,25 @@
     method public void onRequestFocus(android.webkit.WebView);
     method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback);
     method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
+    method public boolean showFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams);
   }
 
   public static abstract interface WebChromeClient.CustomViewCallback {
     method public abstract void onCustomViewHidden();
   }
 
+  public static class WebChromeClient.FileChooserParams {
+    ctor public WebChromeClient.FileChooserParams();
+    field public static final int MODE_OPEN_FOLDER = 2; // 0x2
+    field public static final int MODE_OPEN_MULTIPLE = 1; // 0x1
+    field public static final int MODE_SAVE = 4; // 0x4
+    field public java.lang.String acceptTypes;
+    field public boolean capture;
+    field public java.lang.String defaultFilename;
+    field public int mode;
+    field public java.lang.String title;
+  }
+
   public class WebHistoryItem implements java.lang.Cloneable {
     method public android.graphics.Bitmap getFavicon();
     method public java.lang.String getOriginalUrl();
@@ -35670,10 +35807,14 @@
     method public boolean getSplitTrack();
     method public android.graphics.drawable.Drawable getThumb();
     method public int getThumbOffset();
+    method public android.content.res.ColorStateList getThumbTint();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
+    method public void setThumbTint(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -36088,9 +36229,13 @@
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int, int);
+    method public android.content.res.ColorStateList getButtonTint();
+    method public android.graphics.PorterDuff.Mode getButtonTintMode();
     method public boolean isChecked();
     method public void setButtonDrawable(int);
     method public void setButtonDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonTint(android.content.res.ColorStateList);
+    method public void setButtonTintMode(android.graphics.PorterDuff.Mode);
     method public void setChecked(boolean);
     method public void setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener);
     method public void toggle();
@@ -36351,10 +36496,14 @@
     method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
     method public android.graphics.drawable.Drawable getForeground();
     method public int getForegroundGravity();
+    method public android.content.res.ColorStateList getForegroundTint();
+    method public android.graphics.PorterDuff.Mode getForegroundTintMode();
     method public boolean getMeasureAllChildren();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
+    method public void setForegroundTint(android.content.res.ColorStateList);
+    method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
     method public void setMeasureAllChildren(boolean);
   }
 
@@ -36563,6 +36712,8 @@
     method public int getMaxHeight();
     method public int getMaxWidth();
     method public android.widget.ImageView.ScaleType getScaleType();
+    method public android.content.res.ColorStateList getTint();
+    method public android.graphics.PorterDuff.Mode getTintMode();
     method public int[] onCreateDrawableState(int);
     method public void setAdjustViewBounds(boolean);
     method public deprecated void setAlpha(int);
@@ -36584,6 +36735,8 @@
     method public void setMaxHeight(int);
     method public void setMaxWidth(int);
     method public void setScaleType(android.widget.ImageView.ScaleType);
+    method public void setTint(android.content.res.ColorStateList);
+    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public static final class ImageView.ScaleType extends java.lang.Enum {
@@ -36956,11 +37109,19 @@
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
     method public android.graphics.drawable.Drawable getIndeterminateDrawable();
+    method public android.content.res.ColorStateList getIndeterminateTint();
+    method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method public synchronized int getMax();
     method public synchronized int getProgress();
+    method public android.content.res.ColorStateList getProgressBackgroundTint();
+    method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
     method public android.graphics.drawable.Drawable getProgressDrawable();
+    method public android.content.res.ColorStateList getProgressTint();
+    method public android.graphics.PorterDuff.Mode getProgressTintMode();
     method public synchronized int getSecondaryProgress();
+    method public android.content.res.ColorStateList getSecondaryProgressTint();
+    method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
     method public final synchronized void incrementProgressBy(int);
     method public final synchronized void incrementSecondaryProgressBy(int);
     method public synchronized boolean isIndeterminate();
@@ -36969,13 +37130,21 @@
     method public synchronized void setIndeterminate(boolean);
     method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
     method public void setIndeterminateDrawableTiled(android.graphics.drawable.Drawable);
+    method public void setIndeterminateTint(android.content.res.ColorStateList);
+    method public void setIndeterminateTintMode(android.graphics.PorterDuff.Mode);
     method public void setInterpolator(android.content.Context, int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public synchronized void setMax(int);
     method public synchronized void setProgress(int);
+    method public void setProgressBackgroundTint(android.content.res.ColorStateList);
+    method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
     method public void setProgressDrawable(android.graphics.drawable.Drawable);
     method public void setProgressDrawableTiled(android.graphics.drawable.Drawable);
+    method public void setProgressTint(android.content.res.ColorStateList);
+    method public void setProgressTintMode(android.graphics.PorterDuff.Mode);
     method public synchronized void setSecondaryProgress(int);
+    method public void setSecondaryProgressTint(android.content.res.ColorStateList);
+    method public void setSecondaryProgressTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class QuickContactBadge extends android.widget.ImageView implements android.view.View.OnClickListener {
@@ -37710,6 +37879,7 @@
     method public float getShadowDx();
     method public float getShadowDy();
     method public float getShadowRadius();
+    method public final boolean getShowSoftInputOnFocus();
     method public java.lang.CharSequence getText();
     method public static int getTextColor(android.content.Context, android.content.res.TypedArray, int);
     method public final android.content.res.ColorStateList getTextColors();
@@ -37803,6 +37973,7 @@
     method public void setScroller(android.widget.Scroller);
     method public void setSelectAllOnFocus(boolean);
     method public void setShadowLayer(float, float, float, int);
+    method public final void setShowSoftInputOnFocus(boolean);
     method public void setSingleLine();
     method public void setSingleLine(boolean);
     method public final void setSpannableFactory(android.text.Spannable.Factory);
@@ -39968,109 +40139,6 @@
     field public static final java.lang.Character.UnicodeBlock YI_SYLLABLES;
   }
 
-  public static final class Character.UnicodeScript extends java.lang.Enum {
-    method public static java.lang.Character.UnicodeScript forName(java.lang.String);
-    method public static java.lang.Character.UnicodeScript of(int);
-    method public static java.lang.Character.UnicodeScript valueOf(java.lang.String);
-    method public static final java.lang.Character.UnicodeScript[] values();
-    enum_constant public static final java.lang.Character.UnicodeScript ARABIC;
-    enum_constant public static final java.lang.Character.UnicodeScript ARMENIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript AVESTAN;
-    enum_constant public static final java.lang.Character.UnicodeScript BALINESE;
-    enum_constant public static final java.lang.Character.UnicodeScript BAMUM;
-    enum_constant public static final java.lang.Character.UnicodeScript BATAK;
-    enum_constant public static final java.lang.Character.UnicodeScript BENGALI;
-    enum_constant public static final java.lang.Character.UnicodeScript BOPOMOFO;
-    enum_constant public static final java.lang.Character.UnicodeScript BRAHMI;
-    enum_constant public static final java.lang.Character.UnicodeScript BRAILLE;
-    enum_constant public static final java.lang.Character.UnicodeScript BUGINESE;
-    enum_constant public static final java.lang.Character.UnicodeScript BUHID;
-    enum_constant public static final java.lang.Character.UnicodeScript CANADIAN_ABORIGINAL;
-    enum_constant public static final java.lang.Character.UnicodeScript CARIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript CHAM;
-    enum_constant public static final java.lang.Character.UnicodeScript CHEROKEE;
-    enum_constant public static final java.lang.Character.UnicodeScript COMMON;
-    enum_constant public static final java.lang.Character.UnicodeScript COPTIC;
-    enum_constant public static final java.lang.Character.UnicodeScript CUNEIFORM;
-    enum_constant public static final java.lang.Character.UnicodeScript CYPRIOT;
-    enum_constant public static final java.lang.Character.UnicodeScript CYRILLIC;
-    enum_constant public static final java.lang.Character.UnicodeScript DESERET;
-    enum_constant public static final java.lang.Character.UnicodeScript DEVANAGARI;
-    enum_constant public static final java.lang.Character.UnicodeScript EGYPTIAN_HIEROGLYPHS;
-    enum_constant public static final java.lang.Character.UnicodeScript ETHIOPIC;
-    enum_constant public static final java.lang.Character.UnicodeScript GEORGIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript GLAGOLITIC;
-    enum_constant public static final java.lang.Character.UnicodeScript GOTHIC;
-    enum_constant public static final java.lang.Character.UnicodeScript GREEK;
-    enum_constant public static final java.lang.Character.UnicodeScript GUJARATI;
-    enum_constant public static final java.lang.Character.UnicodeScript GURMUKHI;
-    enum_constant public static final java.lang.Character.UnicodeScript HAN;
-    enum_constant public static final java.lang.Character.UnicodeScript HANGUL;
-    enum_constant public static final java.lang.Character.UnicodeScript HANUNOO;
-    enum_constant public static final java.lang.Character.UnicodeScript HEBREW;
-    enum_constant public static final java.lang.Character.UnicodeScript HIRAGANA;
-    enum_constant public static final java.lang.Character.UnicodeScript IMPERIAL_ARAMAIC;
-    enum_constant public static final java.lang.Character.UnicodeScript INHERITED;
-    enum_constant public static final java.lang.Character.UnicodeScript INSCRIPTIONAL_PAHLAVI;
-    enum_constant public static final java.lang.Character.UnicodeScript INSCRIPTIONAL_PARTHIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript JAVANESE;
-    enum_constant public static final java.lang.Character.UnicodeScript KAITHI;
-    enum_constant public static final java.lang.Character.UnicodeScript KANNADA;
-    enum_constant public static final java.lang.Character.UnicodeScript KATAKANA;
-    enum_constant public static final java.lang.Character.UnicodeScript KAYAH_LI;
-    enum_constant public static final java.lang.Character.UnicodeScript KHAROSHTHI;
-    enum_constant public static final java.lang.Character.UnicodeScript KHMER;
-    enum_constant public static final java.lang.Character.UnicodeScript LAO;
-    enum_constant public static final java.lang.Character.UnicodeScript LATIN;
-    enum_constant public static final java.lang.Character.UnicodeScript LEPCHA;
-    enum_constant public static final java.lang.Character.UnicodeScript LIMBU;
-    enum_constant public static final java.lang.Character.UnicodeScript LINEAR_B;
-    enum_constant public static final java.lang.Character.UnicodeScript LISU;
-    enum_constant public static final java.lang.Character.UnicodeScript LYCIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript LYDIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript MALAYALAM;
-    enum_constant public static final java.lang.Character.UnicodeScript MANDAIC;
-    enum_constant public static final java.lang.Character.UnicodeScript MEETEI_MAYEK;
-    enum_constant public static final java.lang.Character.UnicodeScript MONGOLIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript MYANMAR;
-    enum_constant public static final java.lang.Character.UnicodeScript NEW_TAI_LUE;
-    enum_constant public static final java.lang.Character.UnicodeScript NKO;
-    enum_constant public static final java.lang.Character.UnicodeScript OGHAM;
-    enum_constant public static final java.lang.Character.UnicodeScript OLD_ITALIC;
-    enum_constant public static final java.lang.Character.UnicodeScript OLD_PERSIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript OLD_SOUTH_ARABIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript OLD_TURKIC;
-    enum_constant public static final java.lang.Character.UnicodeScript OL_CHIKI;
-    enum_constant public static final java.lang.Character.UnicodeScript ORIYA;
-    enum_constant public static final java.lang.Character.UnicodeScript OSMANYA;
-    enum_constant public static final java.lang.Character.UnicodeScript PHAGS_PA;
-    enum_constant public static final java.lang.Character.UnicodeScript PHOENICIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript REJANG;
-    enum_constant public static final java.lang.Character.UnicodeScript RUNIC;
-    enum_constant public static final java.lang.Character.UnicodeScript SAMARITAN;
-    enum_constant public static final java.lang.Character.UnicodeScript SAURASHTRA;
-    enum_constant public static final java.lang.Character.UnicodeScript SHAVIAN;
-    enum_constant public static final java.lang.Character.UnicodeScript SINHALA;
-    enum_constant public static final java.lang.Character.UnicodeScript SUNDANESE;
-    enum_constant public static final java.lang.Character.UnicodeScript SYLOTI_NAGRI;
-    enum_constant public static final java.lang.Character.UnicodeScript SYRIAC;
-    enum_constant public static final java.lang.Character.UnicodeScript TAGALOG;
-    enum_constant public static final java.lang.Character.UnicodeScript TAGBANWA;
-    enum_constant public static final java.lang.Character.UnicodeScript TAI_LE;
-    enum_constant public static final java.lang.Character.UnicodeScript TAI_THAM;
-    enum_constant public static final java.lang.Character.UnicodeScript TAI_VIET;
-    enum_constant public static final java.lang.Character.UnicodeScript TAMIL;
-    enum_constant public static final java.lang.Character.UnicodeScript TELUGU;
-    enum_constant public static final java.lang.Character.UnicodeScript THAANA;
-    enum_constant public static final java.lang.Character.UnicodeScript THAI;
-    enum_constant public static final java.lang.Character.UnicodeScript TIBETAN;
-    enum_constant public static final java.lang.Character.UnicodeScript TIFINAGH;
-    enum_constant public static final java.lang.Character.UnicodeScript UGARITIC;
-    enum_constant public static final java.lang.Character.UnicodeScript UNKNOWN;
-    enum_constant public static final java.lang.Character.UnicodeScript VAI;
-    enum_constant public static final java.lang.Character.UnicodeScript YI;
-  }
-
   public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
     method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
     method public T cast(java.lang.Object);
@@ -41911,13 +41979,11 @@
     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);
@@ -42308,11 +42374,6 @@
     method public abstract java.net.SocketImpl createSocketImpl();
   }
 
-  public abstract interface SocketOption {
-    method public abstract java.lang.String name();
-    method public abstract java.lang.Class<T> type();
-  }
-
   public abstract interface SocketOptions {
     method public abstract java.lang.Object getOption(int) throws java.net.SocketException;
     method public abstract void setOption(int, java.lang.Object) throws java.net.SocketException;
@@ -42343,21 +42404,6 @@
     ctor public SocketTimeoutException(java.lang.String);
   }
 
-  public final class StandardSocketOptions {
-    ctor public StandardSocketOptions();
-    field public static final java.net.SocketOption IP_MULTICAST_IF;
-    field public static final java.net.SocketOption IP_MULTICAST_LOOP;
-    field public static final java.net.SocketOption IP_MULTICAST_TTL;
-    field public static final java.net.SocketOption IP_TOS;
-    field public static final java.net.SocketOption SO_BROADCAST;
-    field public static final java.net.SocketOption SO_KEEPALIVE;
-    field public static final java.net.SocketOption SO_LINGER;
-    field public static final java.net.SocketOption SO_RCVBUF;
-    field public static final java.net.SocketOption SO_REUSEADDR;
-    field public static final java.net.SocketOption SO_SNDBUF;
-    field public static final java.net.SocketOption TCP_NODELAY;
-  }
-
   public final class URI implements java.lang.Comparable java.io.Serializable {
     ctor public URI(java.lang.String) throws java.net.URISyntaxException;
     ctor public URI(java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
@@ -42453,7 +42499,6 @@
     method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException;
     method public java.lang.String getContentEncoding();
     method public int getContentLength();
-    method public long getContentLengthLong();
     method public java.lang.String getContentType();
     method public long getDate();
     method public static boolean getDefaultAllowUserInteraction();
@@ -42468,7 +42513,6 @@
     method public long getHeaderFieldDate(java.lang.String, long);
     method public int getHeaderFieldInt(java.lang.String, int);
     method public java.lang.String getHeaderFieldKey(int);
-    method public long getHeaderFieldLong(java.lang.String, long);
     method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> getHeaderFields();
     method public long getIfModifiedSince();
     method public java.io.InputStream getInputStream() throws java.io.IOException;
@@ -42819,10 +42863,6 @@
 
 package java.nio.channels {
 
-  public class AlreadyBoundException extends java.lang.IllegalStateException {
-    ctor public AlreadyBoundException();
-  }
-
   public class AlreadyConnectedException extends java.lang.IllegalStateException {
     ctor public AlreadyConnectedException();
   }
@@ -42870,32 +42910,25 @@
     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.MulticastChannel 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.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;
     method public abstract java.nio.channels.DatagramChannel disconnect() throws java.io.IOException;
-    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;
     method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException;
     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
-    method public java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.DatagramSocket socket();
-    method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
     method public final int validOps();
     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
     method public final synchronized long write(java.nio.ByteBuffer[]) throws java.io.IOException;
   }
 
-  public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel java.nio.channels.SeekableByteChannel {
+  public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
     ctor protected FileChannel();
     method public abstract void force(boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock lock() throws java.io.IOException;
@@ -42927,7 +42960,6 @@
 
   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();
@@ -42960,32 +42992,6 @@
     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;
-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
-    method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
-  }
-
   public class NoConnectionPendingException extends java.lang.IllegalStateException {
     ctor public NoConnectionPendingException();
   }
@@ -43036,15 +43042,6 @@
     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
   }
 
-  public abstract interface SeekableByteChannel implements java.nio.channels.ByteChannel {
-    method public abstract long position() throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel position(long) throws java.io.IOException;
-    method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
-    method public abstract long size() throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel truncate(long) throws java.io.IOException;
-    method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
-  }
-
   public abstract class SelectableChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.Channel {
     ctor protected SelectableChannel();
     method public abstract java.lang.Object blockingLock();
@@ -43093,27 +43090,18 @@
     method public abstract java.nio.channels.Selector wakeup();
   }
 
-  public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.NetworkChannel {
+  public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel {
     ctor protected ServerSocketChannel(java.nio.channels.spi.SelectorProvider);
     method public abstract java.nio.channels.SocketChannel accept() throws java.io.IOException;
-    method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
-    method public java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
-    method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
-    method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
-    method public java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.ServerSocket socket();
-    method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
     method public final int validOps();
   }
 
-  public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
+  public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
     ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
-    method public java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract boolean connect(java.net.SocketAddress) throws java.io.IOException;
     method public abstract boolean finishConnect() throws java.io.IOException;
-    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 abstract boolean isConnectionPending();
     method public static java.nio.channels.SocketChannel open() throws java.io.IOException;
@@ -43121,9 +43109,7 @@
     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;
     method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException;
-    method public java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.Socket socket();
-    method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
     method public final int validOps();
     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
@@ -47083,7 +47069,6 @@
     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);
   }
@@ -47368,13 +47353,6 @@
     method public int getWidth();
   }
 
-  public class IllformedLocaleException extends java.lang.RuntimeException {
-    ctor public IllformedLocaleException();
-    ctor public IllformedLocaleException(java.lang.String);
-    ctor public IllformedLocaleException(java.lang.String, int);
-    method public int getErrorIndex();
-  }
-
   public class InputMismatchException extends java.util.NoSuchElementException implements java.io.Serializable {
     ctor public InputMismatchException();
     ctor public InputMismatchException(java.lang.String);
@@ -47489,7 +47467,6 @@
     ctor public Locale(java.lang.String, java.lang.String);
     ctor public Locale(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.Object clone();
-    method public static java.util.Locale forLanguageTag(java.lang.String);
     method public static java.util.Locale[] getAvailableLocales();
     method public java.lang.String getCountry();
     method public static java.util.Locale getDefault();
@@ -47499,24 +47476,15 @@
     method public java.lang.String getDisplayLanguage(java.util.Locale);
     method public final java.lang.String getDisplayName();
     method public java.lang.String getDisplayName(java.util.Locale);
-    method public java.lang.String getDisplayScript();
-    method public java.lang.String getDisplayScript(java.util.Locale);
     method public final java.lang.String getDisplayVariant();
     method public java.lang.String getDisplayVariant(java.util.Locale);
-    method public java.lang.String getExtension(char);
-    method public java.util.Set<java.lang.Character> getExtensionKeys();
     method public java.lang.String getISO3Country();
     method public java.lang.String getISO3Language();
     method public static java.lang.String[] getISOCountries();
     method public static java.lang.String[] getISOLanguages();
     method public java.lang.String getLanguage();
-    method public java.lang.String getScript();
-    method public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
-    method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
-    method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
     method public static synchronized void setDefault(java.util.Locale);
-    method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
     field public static final java.util.Locale CANADA_FRENCH;
@@ -47534,33 +47502,14 @@
     field public static final java.util.Locale KOREA;
     field public static final java.util.Locale KOREAN;
     field public static final java.util.Locale PRC;
-    field public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x'
     field public static final java.util.Locale ROOT;
     field public static final java.util.Locale SIMPLIFIED_CHINESE;
     field public static final java.util.Locale TAIWAN;
     field public static final java.util.Locale TRADITIONAL_CHINESE;
     field public static final java.util.Locale UK;
-    field public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u'
     field public static final java.util.Locale US;
   }
 
-  public static final class Locale.Builder {
-    ctor public Locale.Builder();
-    method public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String);
-    method public java.util.Locale build();
-    method public java.util.Locale.Builder clear();
-    method public java.util.Locale.Builder clearExtensions();
-    method public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String);
-    method public java.util.Locale.Builder setExtension(char, java.lang.String);
-    method public java.util.Locale.Builder setLanguage(java.lang.String);
-    method public java.util.Locale.Builder setLanguageTag(java.lang.String);
-    method public java.util.Locale.Builder setLocale(java.util.Locale);
-    method public java.util.Locale.Builder setRegion(java.lang.String);
-    method public java.util.Locale.Builder setScript(java.lang.String);
-    method public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String, java.lang.String);
-    method public java.util.Locale.Builder setVariant(java.lang.String);
-  }
-
   public abstract interface Map {
     method public abstract void clear();
     method public abstract boolean containsKey(java.lang.Object);
@@ -48247,35 +48196,6 @@
     method public V replace(K, V);
   }
 
-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
-    ctor public ConcurrentLinkedDeque();
-    ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
-    method public void addFirst(E);
-    method public void addLast(E);
-    method public java.util.Iterator<E> descendingIterator();
-    method public E element();
-    method public E getFirst();
-    method public E getLast();
-    method public java.util.Iterator<E> iterator();
-    method public boolean offer(E);
-    method public boolean offerFirst(E);
-    method public boolean offerLast(E);
-    method public E peek();
-    method public E peekFirst();
-    method public E peekLast();
-    method public E poll();
-    method public E pollFirst();
-    method public E pollLast();
-    method public E pop();
-    method public void push(E);
-    method public E remove();
-    method public E removeFirst();
-    method public boolean removeFirstOccurrence(java.lang.Object);
-    method public E removeLast();
-    method public boolean removeLastOccurrence(java.lang.Object);
-    method public int size();
-  }
-
   public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
@@ -48516,94 +48436,6 @@
     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
   }
 
-  public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService {
-    ctor public ForkJoinPool();
-    ctor public ForkJoinPool(int);
-    ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
-    method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
-    method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
-    method public void execute(java.util.concurrent.ForkJoinTask<?>);
-    method public void execute(java.lang.Runnable);
-    method public int getActiveThreadCount();
-    method public boolean getAsyncMode();
-    method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory();
-    method public int getParallelism();
-    method public int getPoolSize();
-    method public int getQueuedSubmissionCount();
-    method public long getQueuedTaskCount();
-    method public int getRunningThreadCount();
-    method public long getStealCount();
-    method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
-    method public boolean hasQueuedSubmissions();
-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
-    method public boolean isQuiescent();
-    method public boolean isShutdown();
-    method public boolean isTerminated();
-    method public boolean isTerminating();
-    method public static void managedBlock(java.util.concurrent.ForkJoinPool.ManagedBlocker) throws java.lang.InterruptedException;
-    method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
-    method public void shutdown();
-    method public java.util.List<java.lang.Runnable> shutdownNow();
-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
-    field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
-  }
-
-  public static abstract interface ForkJoinPool.ForkJoinWorkerThreadFactory {
-    method public abstract java.util.concurrent.ForkJoinWorkerThread newThread(java.util.concurrent.ForkJoinPool);
-  }
-
-  public static abstract interface ForkJoinPool.ManagedBlocker {
-    method public abstract boolean block() throws java.lang.InterruptedException;
-    method public abstract boolean isReleasable();
-  }
-
-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
-    ctor public ForkJoinTask();
-    method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
-    method public boolean cancel(boolean);
-    method public void complete(V);
-    method public void completeExceptionally(java.lang.Throwable);
-    method protected abstract boolean exec();
-    method public final java.util.concurrent.ForkJoinTask<V> fork();
-    method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method public final java.lang.Throwable getException();
-    method public static java.util.concurrent.ForkJoinPool getPool();
-    method public static int getQueuedTaskCount();
-    method public abstract V getRawResult();
-    method public static int getSurplusQueuedTaskCount();
-    method public static void helpQuiesce();
-    method public static boolean inForkJoinPool();
-    method public final V invoke();
-    method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
-    method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
-    method public final boolean isCancelled();
-    method public final boolean isCompletedAbnormally();
-    method public final boolean isCompletedNormally();
-    method public final boolean isDone();
-    method public final V join();
-    method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask();
-    method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask();
-    method protected static java.util.concurrent.ForkJoinTask<?> pollTask();
-    method public final void quietlyInvoke();
-    method public final void quietlyJoin();
-    method public void reinitialize();
-    method protected abstract void setRawResult(V);
-    method public boolean tryUnfork();
-  }
-
-  public class ForkJoinWorkerThread extends java.lang.Thread {
-    ctor protected ForkJoinWorkerThread(java.util.concurrent.ForkJoinPool);
-    method public java.util.concurrent.ForkJoinPool getPool();
-    method public int getPoolIndex();
-    method protected void onStart();
-    method protected void onTermination(java.lang.Throwable);
-  }
-
   public abstract interface Future {
     method public abstract boolean cancel(boolean);
     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
@@ -48688,52 +48520,6 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
-    ctor public LinkedTransferQueue();
-    ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
-    method public int drainTo(java.util.Collection<? super E>);
-    method public int drainTo(java.util.Collection<? super E>, int);
-    method public int getWaitingConsumerCount();
-    method public boolean hasWaitingConsumer();
-    method public java.util.Iterator<E> iterator();
-    method public boolean offer(E, long, java.util.concurrent.TimeUnit);
-    method public boolean offer(E);
-    method public E peek();
-    method public E poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public E poll();
-    method public void put(E);
-    method public int remainingCapacity();
-    method public int size();
-    method public E take() throws java.lang.InterruptedException;
-    method public void transfer(E) throws java.lang.InterruptedException;
-    method public boolean tryTransfer(E);
-    method public boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-  }
-
-  public class Phaser {
-    ctor public Phaser();
-    ctor public Phaser(int);
-    ctor public Phaser(java.util.concurrent.Phaser);
-    ctor public Phaser(java.util.concurrent.Phaser, int);
-    method public int arrive();
-    method public int arriveAndAwaitAdvance();
-    method public int arriveAndDeregister();
-    method public int awaitAdvance(int);
-    method public int awaitAdvanceInterruptibly(int) throws java.lang.InterruptedException;
-    method public int awaitAdvanceInterruptibly(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method public int bulkRegister(int);
-    method public void forceTermination();
-    method public int getArrivedParties();
-    method public java.util.concurrent.Phaser getParent();
-    method public final int getPhase();
-    method public int getRegisteredParties();
-    method public java.util.concurrent.Phaser getRoot();
-    method public int getUnarrivedParties();
-    method public boolean isTerminated();
-    method protected boolean onAdvance(int, int);
-    method public int register();
-  }
-
   public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public PriorityBlockingQueue();
     ctor public PriorityBlockingQueue(int);
@@ -48754,22 +48540,6 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract class RecursiveAction extends java.util.concurrent.ForkJoinTask {
-    ctor public RecursiveAction();
-    method protected abstract void compute();
-    method protected final boolean exec();
-    method public final java.lang.Void getRawResult();
-    method protected final void setRawResult(java.lang.Void);
-  }
-
-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
-    ctor public RecursiveTask();
-    method protected abstract V compute();
-    method protected final boolean exec();
-    method public final V getRawResult();
-    method protected final void setRawResult(V);
-  }
-
   public class RejectedExecutionException extends java.lang.RuntimeException {
     ctor public RejectedExecutionException();
     ctor public RejectedExecutionException(java.lang.String);
@@ -48808,14 +48578,12 @@
     method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
-    method public boolean getRemoveOnCancelPolicy();
     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
     method public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean);
-    method public void setRemoveOnCancelPolicy(boolean);
   }
 
   public class Semaphore implements java.io.Serializable {
@@ -48861,15 +48629,6 @@
     method public abstract java.lang.Thread newThread(java.lang.Runnable);
   }
 
-  public class ThreadLocalRandom extends java.util.Random {
-    method public static java.util.concurrent.ThreadLocalRandom current();
-    method public double nextDouble(double);
-    method public double nextDouble(double, double);
-    method public int nextInt(int, int);
-    method public long nextLong(long);
-    method public long nextLong(long, long);
-  }
-
   public class ThreadPoolExecutor extends java.util.concurrent.AbstractExecutorService {
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>);
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory);
@@ -48957,14 +48716,6 @@
     ctor public TimeoutException(java.lang.String);
   }
 
-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
-    method public abstract int getWaitingConsumerCount();
-    method public abstract boolean hasWaitingConsumer();
-    method public abstract void transfer(E) throws java.lang.InterruptedException;
-    method public abstract boolean tryTransfer(E);
-    method public abstract boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-  }
-
 }
 
 package java.util.concurrent.atomic {
@@ -49174,7 +48925,6 @@
     method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method public final boolean hasContended();
-    method public final boolean hasQueuedPredecessors();
     method public final boolean hasQueuedThreads();
     method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method protected boolean isHeldExclusively();
@@ -49221,7 +48971,6 @@
     method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method public final boolean hasContended();
-    method public final boolean hasQueuedPredecessors();
     method public final boolean hasQueuedThreads();
     method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method protected boolean isHeldExclusively();
@@ -50166,10 +49915,8 @@
 
   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();
@@ -50223,7 +49970,6 @@
 
   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;
@@ -50271,7 +50017,6 @@
 
   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);
@@ -51770,7 +51515,6 @@
     method public abstract boolean getEnableSessionCreation();
     method public abstract java.lang.String[] getEnabledCipherSuites();
     method public abstract java.lang.String[] getEnabledProtocols();
-    method public javax.net.ssl.SSLSession getHandshakeSession();
     method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
     method public abstract boolean getNeedClientAuth();
     method public java.lang.String getPeerHost();
@@ -51844,12 +51588,10 @@
     ctor public SSLParameters(java.lang.String[]);
     ctor public SSLParameters(java.lang.String[], java.lang.String[]);
     method public java.lang.String[] getCipherSuites();
-    method public java.lang.String getEndpointIdentificationAlgorithm();
     method public boolean getNeedClientAuth();
     method public java.lang.String[] getProtocols();
     method public boolean getWantClientAuth();
     method public void setCipherSuites(java.lang.String[]);
-    method public void setEndpointIdentificationAlgorithm(java.lang.String);
     method public void setNeedClientAuth(boolean);
     method public void setProtocols(java.lang.String[]);
     method public void setWantClientAuth(boolean);
@@ -51950,7 +51692,6 @@
     method public abstract boolean getEnableSessionCreation();
     method public abstract java.lang.String[] getEnabledCipherSuites();
     method public abstract java.lang.String[] getEnabledProtocols();
-    method public javax.net.ssl.SSLSession getHandshakeSession();
     method public abstract boolean getNeedClientAuth();
     method public javax.net.ssl.SSLParameters getSSLParameters();
     method public abstract javax.net.ssl.SSLSession getSession();
@@ -52006,14 +51747,6 @@
     method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine);
   }
 
-  public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager {
-    ctor public X509ExtendedTrustManager();
-    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
-    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
-    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
-    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
-  }
-
   public abstract interface X509KeyManager implements javax.net.ssl.KeyManager {
     method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket);
     method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 8945526..127b0fc 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -32,6 +32,7 @@
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
@@ -43,8 +44,11 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.AndroidException;
 import android.view.IWindowManager;
+import android.view.View;
+
 import com.android.internal.os.BaseCommand;
 
 import dalvik.system.VMRuntime;
@@ -123,6 +127,7 @@
                 "       am stack info <STACK_ID>\n" +
                 "       am lock-task <TASK_ID>\n" +
                 "       am lock-task stop\n" +
+                "       am get-config\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -229,6 +234,9 @@
                 "\n" +
                 "am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
                 "\n" +
+                "am get-config: retrieve the configuration and any recent configurations\n" +
+                "  of the device\n" +
+                "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                 "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
@@ -323,6 +331,8 @@
             runStack();
         } else if (op.equals("lock-task")) {
             runLockTask();
+        } else if (op.equals("get-config")) {
+            runGetConfig();
         } else {
             showError("Error: unknown command '" + op + "'");
         }
@@ -909,8 +919,7 @@
             }
         }
 
-        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
-                abi)) {
+        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) {
             throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
         }
 
@@ -1699,4 +1708,19 @@
         } catch (RemoteException e) {
         }
     }
+
+    private void runGetConfig() throws Exception {
+        try {
+            Configuration config = mAm.getConfiguration();
+            if (config == null) {
+                System.err.println("Activity manager has no configuration");
+                return;
+            }
+
+            System.out.println("config: " + Configuration.resourceQualifierString(config));
+            System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS));
+
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index db3d8bb..d1bea2e 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 
 public final class Bmgr {
@@ -102,6 +103,11 @@
             return;
         }
 
+        if ("fullbackup".equals(op)) {
+            doFullTransportBackup();
+            return;
+        }
+
         System.err.println("Unknown command");
         showUsage();
     }
@@ -165,6 +171,21 @@
         }
     }
 
+    private void doFullTransportBackup() {
+        System.out.println("Performing full transport backup");
+
+        String pkg;
+        while ((pkg = nextArg()) != null) {
+            System.out.println("    Package " + pkg + " ...");
+            try {
+                mBmgr.fullTransportBackup(new String[] { pkg });
+            } catch (RemoteException e) {
+                System.err.println(e.toString());
+                System.err.println(BMGR_NOT_RUNNING_ERR);
+            }
+        }
+    }
+
     private void doTransport() {
         try {
             String which = nextArg();
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java
index 4503726..ffc0f87 100644
--- a/cmds/bu/src/com/android/commands/bu/Backup.java
+++ b/cmds/bu/src/com/android/commands/bu/Backup.java
@@ -69,6 +69,7 @@
         boolean doEverything = false;
         boolean doWidgets = false;
         boolean allIncludesSystem = true;
+        boolean doCompress = true;
 
         String arg;
         while ((arg = nextArg()) != null) {
@@ -95,6 +96,10 @@
                     doWidgets = false;
                 } else if ("-all".equals(arg)) {
                     doEverything = true;
+                } else if ("-compress".equals(arg)) {
+                    doCompress = true;
+                } else if ("-nocompress".equals(arg)) {
+                    doCompress = false;
                 } else {
                     Log.w(TAG, "Unknown backup flag " + arg);
                     continue;
@@ -119,7 +124,7 @@
             fd = ParcelFileDescriptor.adoptFd(socketFd);
             String[] packArray = new String[packages.size()];
             mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doWidgets,
-                    doEverything, allIncludesSystem, packages.toArray(packArray));
+                    doEverything, allIncludesSystem, doCompress, packages.toArray(packArray));
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to invoke backup manager for backup");
         } finally {
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index dce0a75..e6847a9 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,6 +20,7 @@
 import android.app.IActivityManager;
 import android.app.IActivityManager.ContentProviderHolder;
 import android.content.IContentProvider;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -33,7 +34,8 @@
     enum CommandVerb {
         UNSPECIFIED,
         GET,
-        PUT
+        PUT,
+        DELETE
     }
 
     static String[] mArgs;
@@ -74,6 +76,8 @@
                         mVerb = CommandVerb.GET;
                     } else if ("put".equalsIgnoreCase(arg)) {
                         mVerb = CommandVerb.PUT;
+                    } else if ("delete".equalsIgnoreCase(arg)) {
+                        mVerb = CommandVerb.DELETE;
                     } else {
                         // invalid
                         System.err.println("Invalid command: " + arg);
@@ -87,7 +91,7 @@
                         break;  // invalid
                     }
                     mTable = arg.toLowerCase();
-                } else if (mVerb == CommandVerb.GET) {
+                } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
                     mKey = arg;
                     if (mNextArg >= mArgs.length) {
                         valid = true;
@@ -136,6 +140,10 @@
                         case PUT:
                             putForUser(provider, mUser, mTable, mKey, mValue);
                             break;
+                        case DELETE:
+                            System.out.println("Deleted "
+                                    + deleteForUser(provider, mUser, mTable, mKey) + " rows");
+                            break;
                         default:
                             System.err.println("Unspecified command");
                             break;
@@ -211,9 +219,31 @@
         }
     }
 
+    int deleteForUser(IContentProvider provider, int userHandle,
+            final String table, final String key) {
+        Uri targetUri;
+        if ("system".equals(table)) targetUri = Settings.System.getUriFor(key);
+        else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key);
+        else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key);
+        else {
+            System.err.println("Invalid table; no delete performed");
+            throw new IllegalArgumentException("Invalid table " + table);
+        }
+
+        int num = 0;
+        try {
+            num = provider.delete(null, targetUri, null, null);
+        } catch (RemoteException e) {
+            System.err.println("Can't clear key " + key + " in " + table + " for user "
+                    + userHandle);
+        }
+        return num;
+    }
+
     private static void printUsage() {
         System.err.println("usage:  settings [--user NUM] get namespace key");
         System.err.println("        settings [--user NUM] put namespace key value");
+        System.err.println("        settings [--user NUM] delete namespace key");
         System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
         System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
     }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 2620c44..cbc8150 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -462,7 +462,9 @@
      * anything behind it, then only the modal window will be reported
      * (assuming it is the top one). For convenience the returned windows
      * are ordered in a descending layer order, which is the windows that
-     * are higher in the Z-order are reported first.
+     * are higher in the Z-order are reported first. Since the user can always
+     * interact with the window that has input focus by typing, the focused
+     * window is always returned (even if covered by a modal window).
      * <p>
      * <strong>Note:</strong> In order to access the windows your service has
      * to declare the capability to retrieve window content by setting the
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4f9ba59..4edb0c6 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -286,8 +286,8 @@
     /**
      * This flag indicates to the system that the accessibility service wants
      * to access content of all interactive windows. An interactive window is a
-     * window that can be touched by a sighted user when explore by touch is not
-     * enabled. If this flag is not set your service will not receive
+     * window that has input focus or can be touched by a sighted user when explore
+     * by touch is not enabled. If this flag is not set your service will not receive
      * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
      * events, calling AccessibilityService{@link AccessibilityService#getWindows()
      * AccessibilityService.getWindows()} will return an empty list, and {@link
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 12fcdcf..806a55b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -359,7 +359,29 @@
      */
     public AuthenticatorDescription[] getAuthenticatorTypes() {
         try {
-            return mService.getAuthenticatorTypes();
+            return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
+        } catch (RemoteException e) {
+            // will never happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @hide
+     * Lists the currently registered authenticators for a given user id.
+     *
+     * <p>It is safe to call this method from the main thread.
+     *
+     * <p>The caller has to be in the same user or have the permission
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+     *
+     * @return An array of {@link AuthenticatorDescription} for every
+     *     authenticator known to the AccountManager service.  Empty (never
+     *     null) if no authenticators are known.
+     */
+    public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
+        try {
+            return mService.getAuthenticatorTypes(userId);
         } catch (RemoteException e) {
             // will never happen
             throw new RuntimeException(e);
@@ -389,6 +411,28 @@
 
     /**
      * @hide
+     * Lists all accounts of any type registered on the device for a given
+     * user id. Equivalent to getAccountsByType(null).
+     *
+     * <p>It is safe to call this method from the main thread.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     *
+     * @return An array of {@link Account}, one for each account.  Empty
+     *     (never null) if no accounts have been added.
+     */
+    public Account[] getAccountsAsUser(int userId) {
+        try {
+            return mService.getAccountsAsUser(null, userId);
+        } catch (RemoteException e) {
+            // won't ever happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @hide
      * For use by internal activities. Returns the list of accounts that the calling package
      * is authorized to use, particularly for shared accounts.
      * @param packageName package name of the calling app.
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 86e279f..1373dc8 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -29,7 +29,7 @@
 interface IAccountManager {
     String getPassword(in Account account);
     String getUserData(in Account account, String key);
-    AuthenticatorDescription[] getAuthenticatorTypes();
+    AuthenticatorDescription[] getAuthenticatorTypes(int userId);
     Account[] getAccounts(String accountType);
     Account[] getAccountsForPackage(String packageName, int uid);
     Account[] getAccountsByTypeForPackage(String type, String packageName);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 933135d..06f5aca 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.content.res.Resources.NotFoundException;
@@ -25,6 +26,9 @@
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.animation.AnimationUtils;
+
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -66,11 +70,26 @@
      */
     public static Animator loadAnimator(Context context, int id)
             throws NotFoundException {
+        return loadAnimator(context.getResources(), context.getTheme(), id);
+    }
+
+    /**
+     * Loads an {@link Animator} object from a resource
+     *
+     * @param resources The resources
+     * @param theme The theme
+     * @param id The resource id of the animation to load
+     * @return The animator object reference by the specified id
+     * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
+     * @hide
+     */
+    public static Animator loadAnimator(Resources resources, Theme theme, int id)
+            throws NotFoundException {
 
         XmlResourceParser parser = null;
         try {
-            parser = context.getResources().getAnimation(id);
-            return createAnimatorFromXml(context, parser);
+            parser = resources.getAnimation(id);
+            return createAnimatorFromXml(resources, theme, parser);
         } catch (XmlPullParserException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException("Can't load animation resource ID #0x" +
@@ -150,7 +169,8 @@
 
                         }
                         if (animator == null) {
-                            animator = createAnimatorFromXml(context, parser);
+                            animator = createAnimatorFromXml(context.getResources(),
+                                    context.getTheme(), parser);
                         }
 
                         if (animator == null) {
@@ -166,103 +186,8 @@
         }
     }
 
-    private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
-    }
 
-    private static Animator createAnimatorFromXml(Context c, XmlPullParser parser,
-            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
-            throws XmlPullParserException, IOException {
-
-        Animator anim = null;
-        ArrayList<Animator> childAnims = null;
-
-        // Make sure we are on a start tag.
-        int type;
-        int depth = parser.getDepth();
-
-        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
-               && type != XmlPullParser.END_DOCUMENT) {
-
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            String  name = parser.getName();
-
-            if (name.equals("objectAnimator")) {
-                anim = loadObjectAnimator(c, attrs);
-            } else if (name.equals("animator")) {
-                anim = loadAnimator(c, attrs, null);
-            } else if (name.equals("set")) {
-                anim = new AnimatorSet();
-                TypedArray a = c.obtainStyledAttributes(attrs,
-                        com.android.internal.R.styleable.AnimatorSet);
-                int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
-                        TOGETHER);
-                createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim,  ordering);
-                a.recycle();
-            } else {
-                throw new RuntimeException("Unknown animator name: " + parser.getName());
-            }
-
-            if (parent != null) {
-                if (childAnims == null) {
-                    childAnims = new ArrayList<Animator>();
-                }
-                childAnims.add(anim);
-            }
-        }
-        if (parent != null && childAnims != null) {
-            Animator[] animsArray = new Animator[childAnims.size()];
-            int index = 0;
-            for (Animator a : childAnims) {
-                animsArray[index++] = a;
-            }
-            if (sequenceOrdering == TOGETHER) {
-                parent.playTogether(animsArray);
-            } else {
-                parent.playSequentially(animsArray);
-            }
-        }
-
-        return anim;
-
-    }
-
-    private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs)
-            throws NotFoundException {
-
-        ObjectAnimator anim = new ObjectAnimator();
-
-        loadAnimator(context, attrs, anim);
-
-        TypedArray a =
-                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.PropertyAnimator);
-
-        String propertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName);
-
-        anim.setPropertyName(propertyName);
-
-        a.recycle();
-
-        return anim;
-    }
-
-    /**
-     * Creates a new animation whose parameters come from the specified context and
-     * attributes set.
-     *
-     * @param context the application environment
-     * @param attrs the set of attributes holding the animation parameters
-     */
-    private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim)
-            throws NotFoundException {
-
-        TypedArray a =
-                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator);
-
+    private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray a) {
         long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300);
 
         long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0);
@@ -378,11 +303,123 @@
         if (evaluator != null) {
             anim.setEvaluator(evaluator);
         }
+    }
+
+    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0);
+    }
+
+    private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
+            AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
+            throws XmlPullParserException, IOException {
+
+        Animator anim = null;
+        ArrayList<Animator> childAnims = null;
+
+        // Make sure we are on a start tag.
+        int type;
+        int depth = parser.getDepth();
+
+        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                && type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+
+            if (name.equals("objectAnimator")) {
+                anim = loadObjectAnimator(res, theme, attrs);
+            } else if (name.equals("animator")) {
+                anim = loadAnimator(res, theme, attrs, null);
+            } else if (name.equals("set")) {
+                anim = new AnimatorSet();
+                TypedArray a;
+                if (theme != null) {
+                    a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimatorSet, 0, 0);
+                } else {
+                    a = res.obtainAttributes(attrs, com.android.internal.R.styleable.AnimatorSet);
+                }
+                int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
+                        TOGETHER);
+                createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering);
+                a.recycle();
+            } else {
+                throw new RuntimeException("Unknown animator name: " + parser.getName());
+            }
+
+            if (parent != null) {
+                if (childAnims == null) {
+                    childAnims = new ArrayList<Animator>();
+                }
+                childAnims.add(anim);
+            }
+        }
+        if (parent != null && childAnims != null) {
+            Animator[] animsArray = new Animator[childAnims.size()];
+            int index = 0;
+            for (Animator a : childAnims) {
+                animsArray[index++] = a;
+            }
+            if (sequenceOrdering == TOGETHER) {
+                parent.playTogether(animsArray);
+            } else {
+                parent.playSequentially(animsArray);
+            }
+        }
+
+        return anim;
+
+    }
+
+    private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs)
+            throws NotFoundException {
+        ObjectAnimator anim = new ObjectAnimator();
+
+        loadAnimator(res, theme, attrs, anim);
+
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyAnimator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
+        }
+
+        String propertyName = a.getString(R.styleable.PropertyAnimator_propertyName);
+
+        anim.setPropertyName(propertyName);
+
+        a.recycle();
+
+        return anim;
+    }
+
+    /**
+     * Creates a new animation whose parameters come from the specified context
+     * and attributes set.
+     *
+     * @param res The resources
+     * @param attrs The set of attributes holding the animation parameters
+     */
+    private static ValueAnimator loadAnimator(Resources res, Theme theme,
+            AttributeSet attrs, ValueAnimator anim)
+            throws NotFoundException {
+
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.Animator);
+        }
+
+        parseAnimatorFromTypeArray(anim, a);
 
         final int resID =
                 a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
         if (resID > 0) {
-            anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID));
+            anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
         }
         a.recycle();
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 23b5f29..f6883e2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5326,7 +5326,8 @@
      *
      * @hide
      */
-    void convertToTranslucent(TranslucentConversionListener callback, ActivityOptions options) {
+    public void convertToTranslucent(TranslucentConversionListener callback, 
+            ActivityOptions options) {
         boolean drawComplete;
         try {
             mTranslucentCallback = callback;
@@ -5615,6 +5616,34 @@
         mExitTransitionListener = listener;
     }
 
+    /**
+     * Postpone the entering activity transition when Activity was started with
+     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+     * android.util.Pair[])}.
+     * <p>This method gives the Activity the ability to delay starting the entering and
+     * shared element transitions until all data is loaded. Until then, the Activity won't
+     * draw into its window, leaving the window transparent. This may also cause the
+     * returning animation to be delayed until data is ready. This method should be
+     * called in {@link #onCreate(android.os.Bundle)} or in
+     * {@link #onActivityReenter(int, android.content.Intent)}.
+     * {@link #startPostponedEnterTransition()} must be called to allow the Activity to
+     * start the transitions. If the Activity did not use
+     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+     * android.util.Pair[])}, then this method does nothing.</p>
+     */
+    public void postponeEnterTransition() {
+        mActivityTransitionState.postponeEnterTransition();
+    }
+
+    /**
+     * Begin postponed transitions after {@link #postponeEnterTransition()} was called.
+     * If postponeEnterTransition() was called, you must call startPostponedEnterTransition()
+     * to have your Activity start drawing.
+     */
+    public void startPostponedEnterTransition() {
+        mActivityTransitionState.startPostponedEnterTransition();
+    }
+
     // ------------------ Internal API ------------------
     
     final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a057c3e..9160452 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -394,8 +394,18 @@
         if (sharedElements != null) {
             for (int i = 0; i < sharedElements.length; i++) {
                 Pair<View, String> sharedElement = sharedElements[i];
-                names.add(sharedElement.second);
-                mappedNames.add(sharedElement.first.getViewName());
+                String sharedElementName = sharedElement.second;
+                if (sharedElementName == null) {
+                    throw new IllegalArgumentException("Shared element name must not be null");
+                }
+                String viewName = sharedElement.first.getViewName();
+                if (viewName == null) {
+                    throw new IllegalArgumentException("Shared elements must have non-null " +
+                            "viewNames");
+                }
+
+                names.add(sharedElementName);
+                mappedNames.add(viewName);
             }
         }
 
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index a4384f8..c7030b0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -129,9 +129,6 @@
     protected static final String KEY_SCALE_TYPE = "shared_element:scaleType";
     protected static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
 
-    // The background fade in/out duration. TODO: Enable tuning this.
-    public static final int FADE_BACKGROUND_DURATION_MS = 300;
-
     protected static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
 
     /**
@@ -209,16 +206,29 @@
     protected ResultReceiver mResultReceiver;
     final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
     final protected boolean mIsReturning;
+    private Runnable mPendingTransition;
+    private boolean mIsStartingTransition;
+
 
     public ActivityTransitionCoordinator(Window window,
             ArrayList<String> allSharedElementNames,
             ArrayList<String> accepted, ArrayList<String> localNames,
             SharedElementListener listener, boolean isReturning) {
+        this(window, allSharedElementNames, listener, isReturning);
+        viewsReady(accepted, localNames);
+    }
+
+    public ActivityTransitionCoordinator(Window window,
+            ArrayList<String> allSharedElementNames,
+            SharedElementListener listener, boolean isReturning) {
         super(new Handler());
         mWindow = window;
         mListener = listener;
         mAllSharedElementNames = allSharedElementNames;
         mIsReturning = isReturning;
+    }
+
+    protected void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
         setSharedElements(accepted, localNames);
         if (getViewsTransition() != null) {
             getDecor().captureTransitioningViews(mTransitioningViews);
@@ -269,6 +279,8 @@
         return names;
     }
 
+    public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }
+
     public static void setViewVisibility(Collection<View> views, int visibility) {
         if (views != null) {
             for (View view : views) {
@@ -281,13 +293,17 @@
         if (transition == null || views == null || views.isEmpty()) {
             return null;
         }
+        // Add the targets to a set containing transition so that transition
+        // remains unaffected. We don't want to modify the targets of transition itself.
         TransitionSet set = new TransitionSet();
-        set.addTransition(transition);
         if (views != null) {
-            for (View view: views) {
+            for (View view : views) {
                 set.addTarget(view);
             }
         }
+        // By adding the transition after addTarget, we prevent addTarget from
+        // affecting transition.
+        set.addTransition(transition);
         return set;
     }
 
@@ -335,6 +351,10 @@
                 String name = mAllSharedElementNames.get(i);
                 View sharedElement = sharedElements.get(name);
                 if (sharedElement != null) {
+                    if (sharedElement.getViewName() == null) {
+                        throw new IllegalArgumentException("Shared elements must have " +
+                                "non-null viewNames");
+                    }
                     mSharedElementNames.add(name);
                     mSharedElements.add(sharedElement);
                 }
@@ -496,6 +516,10 @@
         return bundle;
     }
 
+    protected long getFadeDuration() {
+        return getWindow().getTransitionBackgroundFadeDuration();
+    }
+
     /**
      * Captures placement information for Views with a shared element name for
      * Activity Transitions.
@@ -506,7 +530,7 @@
      * @param transitionArgs Bundle to store shared element placement information.
      * @param tempBounds     A temporary Rect for capturing the current location of views.
      */
-    private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+    protected static void captureSharedElementState(View view, String name, Bundle transitionArgs,
             Rect tempBounds) {
         Bundle sharedElementBundle = new Bundle();
         tempBounds.set(0, 0, view.getWidth(), view.getHeight());
@@ -542,6 +566,32 @@
         transitionArgs.putBundle(name, sharedElementBundle);
     }
 
+
+    protected void startTransition(Runnable runnable) {
+        if (mIsStartingTransition) {
+            mPendingTransition = runnable;
+        } else {
+            mIsStartingTransition = true;
+            runnable.run();
+        }
+    }
+
+    protected void transitionStarted() {
+        mIsStartingTransition = false;
+    }
+
+    protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
+        @Override
+        public void onTransitionStart(Transition transition) {
+            mIsStartingTransition = false;
+            Runnable pending = mPendingTransition;
+            mPendingTransition = null;
+            if (pending != null) {
+                startTransition(pending);
+            }
+        }
+    }
+
     private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
         for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
             if (scaleType == SCALE_TYPE_VALUES[i]) {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index b32e9ad..d94dadd 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -87,6 +87,11 @@
      */
     private boolean mHasExited;
 
+    /**
+     * Postpone painting and starting the enter transition until this is false.
+     */
+    private boolean mIsEnterPostponed;
+
     public ActivityTransitionState() {
     }
 
@@ -140,15 +145,38 @@
         if (mEnterActivityOptions.isReturning()) {
             restoreExitedViews();
             activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
-            mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
-                    resultReceiver, sharedElementNames, mExitingFrom, mExitingTo);
+        }
+        mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
+                resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning());
+
+        if (!mIsEnterPostponed) {
+            startEnter();
+        }
+    }
+
+    public void postponeEnterTransition() {
+        mIsEnterPostponed = true;
+    }
+
+    public void startPostponedEnterTransition() {
+        if (mIsEnterPostponed) {
+            mIsEnterPostponed = false;
+            if (mEnterTransitionCoordinator != null) {
+                startEnter();
+            }
+        }
+    }
+
+    private void startEnter() {
+        if (mEnterActivityOptions.isReturning()) {
+            mEnterTransitionCoordinator.viewsReady(mExitingFrom, mExitingTo);
         } else {
-            mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
-                    resultReceiver, sharedElementNames, null, null);
-            mEnteringNames = sharedElementNames;
+            mEnterTransitionCoordinator.viewsReady(null, null);
+            mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames();
             mEnteringFrom = mEnterTransitionCoordinator.getAcceptedNames();
             mEnteringTo = mEnterTransitionCoordinator.getMappedNames();
         }
+
         mExitingFrom = null;
         mExitingTo = null;
         mEnterActivityOptions = null;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index c29d75e..94ea2c5 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -354,9 +354,11 @@
     private static class ActivityContainerWrapper {
         private final IActivityContainer mIActivityContainer;
         private final CloseGuard mGuard = CloseGuard.get();
+        boolean mOpened; // Protected by mGuard.
 
         ActivityContainerWrapper(IActivityContainer container) {
             mIActivityContainer = container;
+            mOpened = true;
             mGuard.open("release");
         }
 
@@ -424,11 +426,16 @@
         }
 
         void release() {
-            if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
-            try {
-                mIActivityContainer.release();
-                mGuard.close();
-            } catch (RemoteException e) {
+            synchronized (mGuard) {
+                if (mOpened) {
+                    if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+                    try {
+                        mIActivityContainer.release();
+                        mGuard.close();
+                    } catch (RemoteException e) {
+                    }
+                    mOpened = false;
+                }
             }
         }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 5867232..a480219 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -189,7 +189,9 @@
     /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
     public static final int OP_GET_USAGE_STATS = 43;
     /** @hide */
-    public static final int _NUM_OP = 44;
+    public static final int OP_MUTE_MICROPHONE = 44;
+    /** @hide */
+    public static final int _NUM_OP = 45;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -257,6 +259,7 @@
             OP_COARSE_LOCATION,
             OP_COARSE_LOCATION,
             OP_GET_USAGE_STATS,
+            OP_MUTE_MICROPHONE
     };
 
     /**
@@ -308,6 +311,7 @@
             OPSTR_MONITOR_LOCATION,
             OPSTR_MONITOR_HIGH_POWER_LOCATION,
             null,
+            null,
     };
 
     /**
@@ -358,7 +362,8 @@
             "WAKE_LOCK",
             "MONITOR_LOCATION",
             "MONITOR_HIGH_POWER_LOCATION",
-            "GET_USAGE_STATS"
+            "GET_USAGE_STATS",
+            "OP_MUTE_MICROPHONE",
     };
 
     /**
@@ -410,6 +415,7 @@
             null, // no permission for generic location monitoring
             null, // no permission for high power location monitoring
             android.Manifest.permission.PACKAGE_USAGE_STATS,
+            null, // no permission for muting/unmuting microphone
     };
 
     /**
@@ -462,6 +468,7 @@
             null, //MONITOR_LOCATION
             null, //MONITOR_HIGH_POWER_LOCATION
             null, //GET_USAGE_STATS
+            UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE
     };
 
     /**
@@ -512,6 +519,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
+            AppOpsManager.MODE_ALLOWED,
     };
 
     /**
@@ -566,6 +574,7 @@
             false,
             false,
             false,
+            false,
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 89ee145..01a388f 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -16,36 +16,53 @@
 
 package android.app;
 
+import com.android.internal.util.FastPrintWriter;
+
+import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.LogWriter;
-import com.android.internal.util.FastPrintWriter;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collection;
 
 final class BackStackState implements Parcelable {
     final int[] mOps;
     final int mTransition;
     final int mTransitionStyle;
+    final int mCustomTransition;
+    final int mSceneRoot;
     final String mName;
     final int mIndex;
     final int mBreadCrumbTitleRes;
     final CharSequence mBreadCrumbTitleText;
     final int mBreadCrumbShortTitleRes;
     final CharSequence mBreadCrumbShortTitleText;
+    final ArrayList<String> mSharedElementSourceNames;
+    final ArrayList<String> mSharedElementTargetNames;
 
     public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
         int numRemoved = 0;
         BackStackRecord.Op op = bse.mHead;
         while (op != null) {
-            if (op.removed != null) numRemoved += op.removed.size();
+            if (op.removed != null) {
+                numRemoved += op.removed.size();
+            }
             op = op.next;
         }
-        mOps = new int[bse.mNumOp*7 + numRemoved];
+        mOps = new int[bse.mNumOp * 7 + numRemoved];
 
         if (!bse.mAddToBackStack) {
             throw new IllegalStateException("Not on back stack");
@@ -63,7 +80,7 @@
             if (op.removed != null) {
                 final int N = op.removed.size();
                 mOps[pos++] = N;
-                for (int i=0; i<N; i++) {
+                for (int i = 0; i < N; i++) {
                     mOps[pos++] = op.removed.get(i).mIndex;
                 }
             } else {
@@ -79,6 +96,10 @@
         mBreadCrumbTitleText = bse.mBreadCrumbTitleText;
         mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes;
         mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText;
+        mCustomTransition = bse.mCustomTransition;
+        mSceneRoot = bse.mSceneRoot;
+        mSharedElementSourceNames = bse.mSharedElementSourceNames;
+        mSharedElementTargetNames = bse.mSharedElementTargetNames;
     }
 
     public BackStackState(Parcel in) {
@@ -91,6 +112,10 @@
         mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mBreadCrumbShortTitleRes = in.readInt();
         mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mCustomTransition = in.readInt();
+        mSceneRoot = in.readInt();
+        mSharedElementSourceNames = in.createStringArrayList();
+        mSharedElementTargetNames = in.createStringArrayList();
     }
 
     public BackStackRecord instantiate(FragmentManagerImpl fm) {
@@ -100,8 +125,10 @@
         while (pos < mOps.length) {
             BackStackRecord.Op op = new BackStackRecord.Op();
             op.cmd = mOps[pos++];
-            if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
-                    "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
+            if (FragmentManagerImpl.DEBUG) {
+                Log.v(FragmentManagerImpl.TAG,
+                        "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
+            }
             int findex = mOps[pos++];
             if (findex >= 0) {
                 Fragment f = fm.mActive.get(findex);
@@ -116,9 +143,11 @@
             final int N = mOps[pos++];
             if (N > 0) {
                 op.removed = new ArrayList<Fragment>(N);
-                for (int i=0; i<N; i++) {
-                    if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
-                            "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
+                for (int i = 0; i < N; i++) {
+                    if (FragmentManagerImpl.DEBUG) {
+                        Log.v(FragmentManagerImpl.TAG,
+                                "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
+                    }
                     Fragment r = fm.mActive.get(mOps[pos++]);
                     op.removed.add(r);
                 }
@@ -135,6 +164,10 @@
         bse.mBreadCrumbTitleText = mBreadCrumbTitleText;
         bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes;
         bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText;
+        bse.mCustomTransition = mCustomTransition;
+        bse.mSceneRoot = mSceneRoot;
+        bse.mSharedElementSourceNames = mSharedElementSourceNames;
+        bse.mSharedElementTargetNames = mSharedElementTargetNames;
         bse.bumpBackStackNesting(1);
         return bse;
     }
@@ -153,6 +186,10 @@
         TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0);
         dest.writeInt(mBreadCrumbShortTitleRes);
         TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0);
+        dest.writeInt(mCustomTransition);
+        dest.writeInt(mSceneRoot);
+        dest.writeStringList(mSharedElementSourceNames);
+        dest.writeStringList(mSharedElementTargetNames);
     }
 
     public static final Parcelable.Creator<BackStackState> CREATOR
@@ -217,6 +254,11 @@
     int mBreadCrumbShortTitleRes;
     CharSequence mBreadCrumbShortTitleText;
 
+    int mCustomTransition;
+    int mSceneRoot;
+    ArrayList<String> mSharedElementSourceNames;
+    ArrayList<String> mSharedElementTargetNames;
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder(128);
@@ -240,78 +282,112 @@
 
     void dump(String prefix, PrintWriter writer, boolean full) {
         if (full) {
-            writer.print(prefix); writer.print("mName="); writer.print(mName);
-                    writer.print(" mIndex="); writer.print(mIndex);
-                    writer.print(" mCommitted="); writer.println(mCommitted);
+            writer.print(prefix);
+            writer.print("mName=");
+            writer.print(mName);
+            writer.print(" mIndex=");
+            writer.print(mIndex);
+            writer.print(" mCommitted=");
+            writer.println(mCommitted);
             if (mTransition != FragmentTransaction.TRANSIT_NONE) {
-                writer.print(prefix); writer.print("mTransition=#");
-                        writer.print(Integer.toHexString(mTransition));
-                        writer.print(" mTransitionStyle=#");
-                        writer.println(Integer.toHexString(mTransitionStyle));
+                writer.print(prefix);
+                writer.print("mTransition=#");
+                writer.print(Integer.toHexString(mTransition));
+                writer.print(" mTransitionStyle=#");
+                writer.println(Integer.toHexString(mTransitionStyle));
             }
-            if (mEnterAnim != 0 || mExitAnim !=0) {
-                writer.print(prefix); writer.print("mEnterAnim=#");
-                        writer.print(Integer.toHexString(mEnterAnim));
-                        writer.print(" mExitAnim=#");
-                        writer.println(Integer.toHexString(mExitAnim));
+            if (mEnterAnim != 0 || mExitAnim != 0) {
+                writer.print(prefix);
+                writer.print("mEnterAnim=#");
+                writer.print(Integer.toHexString(mEnterAnim));
+                writer.print(" mExitAnim=#");
+                writer.println(Integer.toHexString(mExitAnim));
             }
-            if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
-                writer.print(prefix); writer.print("mPopEnterAnim=#");
-                        writer.print(Integer.toHexString(mPopEnterAnim));
-                        writer.print(" mPopExitAnim=#");
-                        writer.println(Integer.toHexString(mPopExitAnim));
+            if (mPopEnterAnim != 0 || mPopExitAnim != 0) {
+                writer.print(prefix);
+                writer.print("mPopEnterAnim=#");
+                writer.print(Integer.toHexString(mPopEnterAnim));
+                writer.print(" mPopExitAnim=#");
+                writer.println(Integer.toHexString(mPopExitAnim));
             }
             if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
-                writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
-                        writer.print(Integer.toHexString(mBreadCrumbTitleRes));
-                        writer.print(" mBreadCrumbTitleText=");
-                        writer.println(mBreadCrumbTitleText);
+                writer.print(prefix);
+                writer.print("mBreadCrumbTitleRes=#");
+                writer.print(Integer.toHexString(mBreadCrumbTitleRes));
+                writer.print(" mBreadCrumbTitleText=");
+                writer.println(mBreadCrumbTitleText);
             }
             if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
-                writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
-                        writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
-                        writer.print(" mBreadCrumbShortTitleText=");
-                        writer.println(mBreadCrumbShortTitleText);
+                writer.print(prefix);
+                writer.print("mBreadCrumbShortTitleRes=#");
+                writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
+                writer.print(" mBreadCrumbShortTitleText=");
+                writer.println(mBreadCrumbShortTitleText);
             }
         }
 
         if (mHead != null) {
-            writer.print(prefix); writer.println("Operations:");
+            writer.print(prefix);
+            writer.println("Operations:");
             String innerPrefix = prefix + "    ";
             Op op = mHead;
             int num = 0;
             while (op != null) {
                 String cmdStr;
                 switch (op.cmd) {
-                    case OP_NULL: cmdStr="NULL"; break;
-                    case OP_ADD: cmdStr="ADD"; break;
-                    case OP_REPLACE: cmdStr="REPLACE"; break;
-                    case OP_REMOVE: cmdStr="REMOVE"; break;
-                    case OP_HIDE: cmdStr="HIDE"; break;
-                    case OP_SHOW: cmdStr="SHOW"; break;
-                    case OP_DETACH: cmdStr="DETACH"; break;
-                    case OP_ATTACH: cmdStr="ATTACH"; break;
-                    default: cmdStr="cmd=" + op.cmd; break;
+                    case OP_NULL:
+                        cmdStr = "NULL";
+                        break;
+                    case OP_ADD:
+                        cmdStr = "ADD";
+                        break;
+                    case OP_REPLACE:
+                        cmdStr = "REPLACE";
+                        break;
+                    case OP_REMOVE:
+                        cmdStr = "REMOVE";
+                        break;
+                    case OP_HIDE:
+                        cmdStr = "HIDE";
+                        break;
+                    case OP_SHOW:
+                        cmdStr = "SHOW";
+                        break;
+                    case OP_DETACH:
+                        cmdStr = "DETACH";
+                        break;
+                    case OP_ATTACH:
+                        cmdStr = "ATTACH";
+                        break;
+                    default:
+                        cmdStr = "cmd=" + op.cmd;
+                        break;
                 }
-                writer.print(prefix); writer.print("  Op #"); writer.print(num);
-                        writer.print(": "); writer.print(cmdStr);
-                        writer.print(" "); writer.println(op.fragment);
+                writer.print(prefix);
+                writer.print("  Op #");
+                writer.print(num);
+                writer.print(": ");
+                writer.print(cmdStr);
+                writer.print(" ");
+                writer.println(op.fragment);
                 if (full) {
                     if (op.enterAnim != 0 || op.exitAnim != 0) {
-                        writer.print(innerPrefix); writer.print("enterAnim=#");
-                                writer.print(Integer.toHexString(op.enterAnim));
-                                writer.print(" exitAnim=#");
-                                writer.println(Integer.toHexString(op.exitAnim));
+                        writer.print(innerPrefix);
+                        writer.print("enterAnim=#");
+                        writer.print(Integer.toHexString(op.enterAnim));
+                        writer.print(" exitAnim=#");
+                        writer.println(Integer.toHexString(op.exitAnim));
                     }
                     if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
-                        writer.print(innerPrefix); writer.print("popEnterAnim=#");
-                                writer.print(Integer.toHexString(op.popEnterAnim));
-                                writer.print(" popExitAnim=#");
-                                writer.println(Integer.toHexString(op.popExitAnim));
+                        writer.print(innerPrefix);
+                        writer.print("popEnterAnim=#");
+                        writer.print(Integer.toHexString(op.popEnterAnim));
+                        writer.print(" popExitAnim=#");
+                        writer.println(Integer.toHexString(op.popExitAnim));
                     }
                 }
                 if (op.removed != null && op.removed.size() > 0) {
-                    for (int i=0; i<op.removed.size(); i++) {
+                    for (int i = 0; i < op.removed.size(); i++) {
                         writer.print(innerPrefix);
                         if (op.removed.size() == 1) {
                             writer.print("Removed: ");
@@ -319,8 +395,10 @@
                             if (i == 0) {
                                 writer.println("Removed:");
                             }
-                            writer.print(innerPrefix); writer.print("  #"); writer.print(i);
-                                    writer.print(": "); 
+                            writer.print(innerPrefix);
+                            writer.print("  #");
+                            writer.print(i);
+                            writer.print(": ");
                         }
                         writer.println(op.removed.get(i));
                     }
@@ -494,6 +572,51 @@
         return this;
     }
 
+    @Override
+    public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) {
+        mSceneRoot = sceneRootId;
+        mCustomTransition = transitionId;
+        return this;
+    }
+
+    @Override
+    public FragmentTransaction setSharedElement(View sharedElement, String name) {
+        String viewName = sharedElement.getViewName();
+        if (viewName == null) {
+            throw new IllegalArgumentException("Unique viewNames are required for all" +
+                    " sharedElements");
+        }
+        mSharedElementSourceNames = new ArrayList<String>(1);
+        mSharedElementSourceNames.add(viewName);
+
+        mSharedElementTargetNames = new ArrayList<String>(1);
+        mSharedElementTargetNames.add(name);
+        return this;
+    }
+
+    @Override
+    public FragmentTransaction setSharedElements(Pair<View, String>... sharedElements) {
+        if (sharedElements == null || sharedElements.length == 0) {
+            mSharedElementSourceNames = null;
+            mSharedElementTargetNames = null;
+        } else {
+            ArrayList<String> sourceNames = new ArrayList<String>(sharedElements.length);
+            ArrayList<String> targetNames = new ArrayList<String>(sharedElements.length);
+            for (int i = 0; i < sharedElements.length; i++) {
+                String viewName = sharedElements[i].first.getViewName();
+                if (viewName == null) {
+                    throw new IllegalArgumentException("Unique viewNames are required for all" +
+                            " sharedElements");
+                }
+                sourceNames.add(viewName);
+                targetNames.add(sharedElements[i].second);
+            }
+            mSharedElementSourceNames = sourceNames;
+            mSharedElementTargetNames = targetNames;
+        }
+        return this;
+    }
+
     public FragmentTransaction setTransitionStyle(int styleRes) {
         mTransitionStyle = styleRes;
         return this;
@@ -550,21 +673,27 @@
         if (!mAddToBackStack) {
             return;
         }
-        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this
-                + " by " + amt);
+        if (FragmentManagerImpl.DEBUG) {
+            Log.v(TAG, "Bump nesting in " + this
+                    + " by " + amt);
+        }
         Op op = mHead;
         while (op != null) {
             if (op.fragment != null) {
                 op.fragment.mBackStackNesting += amt;
-                if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
-                        + op.fragment + " to " + op.fragment.mBackStackNesting);
+                if (FragmentManagerImpl.DEBUG) {
+                    Log.v(TAG, "Bump nesting of "
+                            + op.fragment + " to " + op.fragment.mBackStackNesting);
+                }
             }
             if (op.removed != null) {
-                for (int i=op.removed.size()-1; i>=0; i--) {
+                for (int i = op.removed.size() - 1; i >= 0; i--) {
                     Fragment r = op.removed.get(i);
                     r.mBackStackNesting += amt;
-                    if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
-                            + r + " to " + r.mBackStackNesting);
+                    if (FragmentManagerImpl.DEBUG) {
+                        Log.v(TAG, "Bump nesting of "
+                                + r + " to " + r.mBackStackNesting);
+                    }
                 }
             }
             op = op.next;
@@ -578,9 +707,11 @@
     public int commitAllowingStateLoss() {
         return commitInternal(true);
     }
-    
+
     int commitInternal(boolean allowStateLoss) {
-        if (mCommitted) throw new IllegalStateException("commit already called");
+        if (mCommitted) {
+            throw new IllegalStateException("commit already called");
+        }
         if (FragmentManagerImpl.DEBUG) {
             Log.v(TAG, "Commit: " + this);
             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -597,9 +728,11 @@
         mManager.enqueueAction(this, allowStateLoss);
         return mIndex;
     }
-    
+
     public void run() {
-        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
+        if (FragmentManagerImpl.DEBUG) {
+            Log.v(TAG, "Run: " + this);
+        }
 
         if (mAddToBackStack) {
             if (mIndex < 0) {
@@ -609,6 +742,9 @@
 
         bumpBackStackNesting(1);
 
+        TransitionState state = beginTransition(mSharedElementSourceNames,
+                mSharedElementTargetNames);
+
         Op op = mHead;
         while (op != null) {
             switch (op.cmd) {
@@ -616,14 +752,17 @@
                     Fragment f = op.fragment;
                     f.mNextAnim = op.enterAnim;
                     mManager.addFragment(f, false);
-                } break;
+                }
+                break;
                 case OP_REPLACE: {
                     Fragment f = op.fragment;
                     if (mManager.mAdded != null) {
-                        for (int i=0; i<mManager.mAdded.size(); i++) {
+                        for (int i = 0; i < mManager.mAdded.size(); i++) {
                             Fragment old = mManager.mAdded.get(i);
-                            if (FragmentManagerImpl.DEBUG) Log.v(TAG,
-                                    "OP_REPLACE: adding=" + f + " old=" + old);
+                            if (FragmentManagerImpl.DEBUG) {
+                                Log.v(TAG,
+                                        "OP_REPLACE: adding=" + f + " old=" + old);
+                            }
                             if (f == null || old.mContainerId == f.mContainerId) {
                                 if (old == f) {
                                     op.fragment = f = null;
@@ -635,8 +774,10 @@
                                     old.mNextAnim = op.exitAnim;
                                     if (mAddToBackStack) {
                                         old.mBackStackNesting += 1;
-                                        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
-                                                + old + " to " + old.mBackStackNesting);
+                                        if (FragmentManagerImpl.DEBUG) {
+                                            Log.v(TAG, "Bump nesting of "
+                                                    + old + " to " + old.mBackStackNesting);
+                                        }
                                     }
                                     mManager.removeFragment(old, mTransition, mTransitionStyle);
                                 }
@@ -647,32 +788,38 @@
                         f.mNextAnim = op.enterAnim;
                         mManager.addFragment(f, false);
                     }
-                } break;
+                }
+                break;
                 case OP_REMOVE: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.exitAnim;
                     mManager.removeFragment(f, mTransition, mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_HIDE: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.exitAnim;
                     mManager.hideFragment(f, mTransition, mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_SHOW: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.enterAnim;
                     mManager.showFragment(f, mTransition, mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_DETACH: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.exitAnim;
                     mManager.detachFragment(f, mTransition, mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_ATTACH: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.enterAnim;
                     mManager.attachFragment(f, mTransition, mTransitionStyle);
-                } break;
+                }
+                break;
                 default: {
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                 }
@@ -687,9 +834,174 @@
         if (mAddToBackStack) {
             mManager.addBackStackState(this);
         }
+
+        if (state != null) {
+            updateTransitionEndState(state, mSharedElementTargetNames);
+        }
     }
 
-    public void popFromBackStack(boolean doStateMove) {
+    private TransitionState beginTransition(ArrayList<String> sourceNames,
+            ArrayList<String> targetNames) {
+        if (mCustomTransition <= 0 || mSceneRoot <= 0) {
+            return null;
+        }
+        View rootView = mManager.mContainer.findViewById(mSceneRoot);
+        if (!(rootView instanceof ViewGroup)) {
+            throw new IllegalArgumentException("SceneRoot is not a ViewGroup");
+        }
+        TransitionState state = new TransitionState();
+        // get Transition scene root and create Transitions
+        state.sceneRoot = (ViewGroup) rootView;
+        state.sceneRoot.captureTransitioningViews(state.transitioningViews);
+
+        state.exitTransition = TransitionInflater.from(mManager.mActivity)
+                .inflateTransition(mCustomTransition);
+        state.sharedElementTransition = TransitionInflater.from(mManager.mActivity)
+                .inflateTransition(mCustomTransition);
+        state.enterTransition = TransitionInflater.from(mManager.mActivity)
+                .inflateTransition(mCustomTransition);
+        // Adding a non-existent target view makes sure that the transitions don't target
+        // any views by default. They'll only target the views we tell add. If we don't
+        // add any, then no views will be targeted.
+        View nonExistentView = new View(mManager.mActivity);
+        state.enterTransition.addTarget(nonExistentView);
+        state.exitTransition.addTarget(nonExistentView);
+        state.sharedElementTransition.addTarget(nonExistentView);
+
+        setSharedElementEpicenter(state.enterTransition, state);
+
+        state.excludingTransition = new TransitionSet()
+                .addTransition(state.exitTransition)
+                .addTransition(state.enterTransition);
+
+        if (sourceNames != null) {
+            // Map shared elements.
+            state.sceneRoot.findNamedViews(state.namedViews);
+            state.namedViews.retainAll(sourceNames);
+            View epicenterView = state.namedViews.get(sourceNames.get(0));
+            if (epicenterView != null) {
+                // The epicenter is only the first shared element.
+                setEpicenter(state.exitTransition, epicenterView);
+                setEpicenter(state.sharedElementTransition, epicenterView);
+            }
+            state.transitioningViews.removeAll(state.namedViews.values());
+            state.excludingTransition.addTransition(state.sharedElementTransition);
+            addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
+        }
+
+        // Adds the (maybe) exiting views, not including the shared element.
+        // If some stay, that's ok.
+        addTransitioningViews(state.exitTransition, state.transitioningViews);
+
+        // Prepare for shared element name mapping. This could be chained in the case
+        // of popping several back stack states.
+        state.excludingTransition.setNameOverrides(new ArrayMap<String, String>());
+        setNameOverrides(state, sourceNames, targetNames);
+
+        // Don't include any subtree in the views that are hidden when capturing the
+        // view hierarchy transitions. They should be as if not there.
+        excludeHiddenFragments(state, true);
+
+        TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition);
+        return state;
+    }
+
+    private void updateTransitionEndState(TransitionState state, ArrayList<String> names) {
+        // Find all views that are entering.
+        ArrayList<View> enteringViews = new ArrayList<View>();
+        state.sceneRoot.captureTransitioningViews(enteringViews);
+        enteringViews.removeAll(state.transitioningViews);
+
+        if (names != null) {
+            // find all shared elements.
+            state.namedViews.clear();
+            state.sceneRoot.findNamedViews(state.namedViews);
+            state.namedViews.retainAll(names);
+            if (!state.namedViews.isEmpty()) {
+                enteringViews.removeAll(state.namedViews.values());
+                addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
+                // now we know the epicenter of the entering transition.
+                state.mEnteringEpicenterView = state.namedViews.get(names.get(0));
+            }
+        }
+
+        // Add all entering views to the enter transition.
+        addTransitioningViews(state.enterTransition, enteringViews);
+
+        // Don't allow capturing state for the newly-hidden fragments.
+        excludeHiddenFragments(state, false);
+
+        // Allow capturing state for the newly-shown fragments
+        includeVisibleFragments(state.excludingTransition);
+    }
+
+    private void addTransitioningViews(Transition transition, Collection<View> views) {
+        if (views.isEmpty()) {
+            // Add a view so that we can modify the valid views at the end of the
+            // fragment transaction.
+            transition.addTarget(new View(mManager.mActivity));
+        } else {
+            for (View view : views) {
+                transition.addTarget(view);
+            }
+        }
+    }
+
+    private void excludeHiddenFragments(TransitionState state, boolean forceExclude) {
+        if (mManager.mAdded != null) {
+            for (int i = 0; i < mManager.mAdded.size(); i++) {
+                Fragment fragment = mManager.mAdded.get(i);
+                if (fragment.mView != null && fragment.mHidden
+                        && (forceExclude || !state.hiddenViews.contains(fragment.mView))) {
+                    state.excludingTransition.excludeTarget(fragment.mView, true);
+                    state.hiddenViews.add(fragment.mView);
+                }
+            }
+        }
+        if (forceExclude && state.hiddenViews.isEmpty()) {
+            state.excludingTransition.excludeTarget(new View(mManager.mActivity), true);
+        }
+    }
+
+    private void includeVisibleFragments(Transition transition) {
+        if (mManager.mAdded != null) {
+            for (int i = 0; i < mManager.mAdded.size(); i++) {
+                Fragment fragment = mManager.mAdded.get(i);
+                if (fragment.mView != null && !fragment.mHidden) {
+                    transition.excludeTarget(fragment.mView, false);
+                }
+            }
+        }
+    }
+
+    private static void setEpicenter(Transition transition, View view) {
+        final Rect epicenter = new Rect();
+        view.getBoundsOnScreen(epicenter);
+
+        transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return epicenter;
+            }
+        });
+    }
+
+    private void setSharedElementEpicenter(Transition transition, final TransitionState state) {
+        transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            private Rect mEpicenter;
+
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                if (mEpicenter == null && state.mEnteringEpicenterView != null) {
+                    mEpicenter = new Rect();
+                    state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter);
+                }
+                return mEpicenter;
+            }
+        });
+    }
+
+    public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) {
         if (FragmentManagerImpl.DEBUG) {
             Log.v(TAG, "popFromBackStack: " + this);
             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -698,6 +1010,12 @@
             pw.flush();
         }
 
+        if (state == null) {
+            state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames);
+        } else {
+            setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
+        }
+
         bumpBackStackNesting(-1);
 
         Op op = mTail;
@@ -709,7 +1027,8 @@
                     mManager.removeFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition),
                             mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_REPLACE: {
                     Fragment f = op.fragment;
                     if (f != null) {
@@ -719,42 +1038,48 @@
                                 mTransitionStyle);
                     }
                     if (op.removed != null) {
-                        for (int i=0; i<op.removed.size(); i++) {
+                        for (int i = 0; i < op.removed.size(); i++) {
                             Fragment old = op.removed.get(i);
                             old.mNextAnim = op.popEnterAnim;
                             mManager.addFragment(old, false);
                         }
                     }
-                } break;
+                }
+                break;
                 case OP_REMOVE: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.popEnterAnim;
                     mManager.addFragment(f, false);
-                } break;
+                }
+                break;
                 case OP_HIDE: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.popEnterAnim;
                     mManager.showFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_SHOW: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.popExitAnim;
                     mManager.hideFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_DETACH: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.popEnterAnim;
                     mManager.attachFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                } break;
+                }
+                break;
                 case OP_ATTACH: {
                     Fragment f = op.fragment;
                     f.mNextAnim = op.popExitAnim;
                     mManager.detachFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                } break;
+                }
+                break;
                 default: {
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                 }
@@ -766,12 +1091,39 @@
         if (doStateMove) {
             mManager.moveToState(mManager.mCurState,
                     FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
+            if (state != null) {
+                updateTransitionEndState(state, mSharedElementSourceNames);
+                state = null;
+            }
         }
 
         if (mIndex >= 0) {
             mManager.freeBackStackIndex(mIndex);
             mIndex = -1;
         }
+        return state;
+    }
+
+    private static void setNameOverride(Transition transition, String source, String target) {
+        ArrayMap<String, String> overrides = transition.getNameOverrides();
+        for (int index = 0; index < overrides.size(); index++) {
+            if (source.equals(overrides.valueAt(index))) {
+                overrides.setValueAt(index, target);
+                return;
+            }
+        }
+        overrides.put(source, target);
+    }
+
+    private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames,
+            ArrayList<String> targetNames) {
+        if (sourceNames != null) {
+            for (int i = 0; i < sourceNames.size(); i++) {
+                String source = sourceNames.get(i);
+                String target = targetNames.get(i);
+                setNameOverride(state.excludingTransition, source, target);
+            }
+        }
     }
 
     public String getName() {
@@ -789,4 +1141,16 @@
     public boolean isEmpty() {
         return mNumOp == 0;
     }
+
+    public class TransitionState {
+        public ArrayList<View> hiddenViews = new ArrayList<View>();
+        public ArrayList<View> transitioningViews = new ArrayList<View>();
+        public ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
+        public Transition exitTransition;
+        public Transition sharedElementTransition;
+        public Transition enterTransition;
+        public TransitionSet excludingTransition;
+        public ViewGroup sceneRoot;
+        public View mEnteringEpicenterView;
+    }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ad506e4..a42bd3b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -115,9 +115,9 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
+import android.service.fingerprint.IFingerprintService;
 import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
-import android.service.fingerprint.FingerprintService;
+import android.telecomm.TelecommManager;
 import android.telephony.TelephonyManager;
 import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
@@ -135,13 +135,14 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.app.admin.DevicePolicyManager;
-import android.app.task.ITaskManager;
+import android.app.job.IJobScheduler;
 import android.app.trust.TrustManager;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.appwidget.IAppWidgetService.Stub;
 import com.android.internal.os.IDropBoxManagerService;
+import com.android.internal.telecomm.ITelecommService;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -464,11 +465,6 @@
                     return new KeyguardManager();
                 }});
 
-        registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new FingerprintManager(ctx);
-            }});
-
         registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -554,6 +550,13 @@
                     return new TelephonyManager(ctx.getOuterContext());
                 }});
 
+        registerService(TELECOMM_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(TELECOMM_SERVICE);
+                    return new TelecommManager(ctx.getOuterContext(),
+                            ITelecommService.Stub.asInterface(b));
+                }});
+
         registerService(UI_MODE_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     return new UiModeManager();
@@ -681,6 +684,7 @@
                 return new MediaSessionManager(ctx);
             }
         });
+
         registerService(TRUST_SERVICE, new ServiceFetcher() {
             public Object createService(ContextImpl ctx) {
                 IBinder b = ServiceManager.getService(TRUST_SERVICE);
@@ -688,6 +692,14 @@
             }
         });
 
+        registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(FINGERPRINT_SERVICE);
+                IFingerprintService service = IFingerprintService.Stub.asInterface(b);
+                return new FingerprintManager(ctx.getOuterContext(), service);
+            }
+        });
+
         registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
             public Object createService(ContextImpl ctx) {
                 IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
@@ -706,10 +718,10 @@
                 return new UsageStatsManager(ctx.getOuterContext());
         }});
 
-        registerService(TASK_SERVICE, new ServiceFetcher() {
+        registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
             public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(TASK_SERVICE);
-                return new TaskManagerImpl(ITaskManager.Stub.asInterface(b));
+                IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
+                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
             }});
     }
 
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 4b052e7..365cc8e 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -53,18 +53,38 @@
     private boolean mIsCanceled;
     private ObjectAnimator mBackgroundAnimator;
     private boolean mIsExitTransitionComplete;
+    private boolean mIsReadyForTransition;
+    private Bundle mSharedElementsBundle;
 
     public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
-            ArrayList<String> sharedElementNames,
-            ArrayList<String> acceptedNames, ArrayList<String> mappedNames) {
-        super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames,
-                getListener(activity, acceptedNames), acceptedNames != null);
+            ArrayList<String> sharedElementNames, boolean isReturning) {
+        super(activity.getWindow(), sharedElementNames,
+                getListener(activity, isReturning), isReturning);
         mActivity = activity;
         setResultReceiver(resultReceiver);
         prepareEnter();
         Bundle resultReceiverBundle = new Bundle();
         resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
         mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
+        getDecor().getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        if (mIsReadyForTransition) {
+                            getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                        }
+                        return mIsReadyForTransition;
+                    }
+                });
+    }
+
+    public void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
+        if (mIsReadyForTransition) {
+            return;
+        }
+        super.viewsReady(accepted, localNames);
+
+        mIsReadyForTransition = true;
         if (mIsReturning) {
             mHandler = new Handler() {
                 @Override
@@ -75,11 +95,27 @@
             mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
             send(MSG_SEND_SHARED_ELEMENT_DESTINATION, null);
         }
+        setViewVisibility(mSharedElements, View.INVISIBLE);
+        if (getViewsTransition() != null) {
+            setViewVisibility(mTransitioningViews, View.INVISIBLE);
+        }
+        if (mSharedElementsBundle != null) {
+            onTakeSharedElements();
+        }
     }
 
     private void sendSharedElementDestination() {
         ViewGroup decor = getDecor();
-        if (!decor.isLayoutRequested()) {
+        boolean allReady = !decor.isLayoutRequested();
+        if (allReady) {
+            for (int i = 0; i < mSharedElements.size(); i++) {
+                if (mSharedElements.get(i).isLayoutRequested()) {
+                    allReady = false;
+                    break;
+                }
+            }
+        }
+        if (allReady) {
             Bundle state = captureSharedElementState();
             mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
         } else {
@@ -88,15 +124,18 @@
                         @Override
                         public boolean onPreDraw() {
                             getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                            Bundle state = captureSharedElementState();
+                            mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
                             return true;
                         }
                     });
         }
+        if (allowOverlappingTransitions()) {
+            startEnterTransitionOnly();
+        }
     }
 
-    private static SharedElementListener getListener(Activity activity,
-            ArrayList<String> acceptedNames) {
-        boolean isReturning = acceptedNames != null;
+    private static SharedElementListener getListener(Activity activity, boolean isReturning) {
         return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener;
     }
 
@@ -108,7 +147,8 @@
                     if (mHandler != null) {
                         mHandler.removeMessages(MSG_CANCEL);
                     }
-                    onTakeSharedElements(resultData);
+                    mSharedElementsBundle = resultData;
+                    onTakeSharedElements();
                 }
                 break;
             case MSG_EXIT_TRANSITION_COMPLETE:
@@ -139,7 +179,7 @@
             mSharedElementNames.clear();
             mSharedElements.clear();
             mAllSharedElementNames.clear();
-            onTakeSharedElements(null);
+            startSharedElementTransition(null);
             onRemoteExitTransitionComplete();
         }
     }
@@ -149,10 +189,6 @@
     }
 
     protected void prepareEnter() {
-        setViewVisibility(mSharedElements, View.INVISIBLE);
-        if (getViewsTransition() != null) {
-            setViewVisibility(mTransitioningViews, View.INVISIBLE);
-        }
         mActivity.overridePendingTransition(0, 0);
         if (!mIsReturning) {
             mActivity.convertToTranslucent(null, null);
@@ -185,7 +221,7 @@
         }
     }
 
-    protected void onTakeSharedElements(Bundle sharedElementState) {
+    private void startSharedElementTransition(Bundle sharedElementState) {
         setEpicenter();
         // Remove rejected shared elements
         ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
@@ -202,7 +238,7 @@
                 setSharedElementState(sharedElementState, sharedElementSnapshots);
         requestLayoutForSharedElements();
 
-        boolean startEnterTransition = allowOverlappingTransitions();
+        boolean startEnterTransition = allowOverlappingTransitions() && !mIsReturning;
         boolean startSharedElementTransition = true;
         Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
 
@@ -218,6 +254,29 @@
         mResultReceiver = null; // all done sending messages.
     }
 
+    private void onTakeSharedElements() {
+        if (!mIsReadyForTransition || mSharedElementsBundle == null) {
+            return;
+        }
+        final Bundle sharedElementState = mSharedElementsBundle;
+        mSharedElementsBundle = null;
+        getDecor().getViewTreeObserver()
+                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                        startTransition(new Runnable() {
+                            @Override
+                            public void run() {
+                                startSharedElementTransition(sharedElementState);
+                            }
+                        });
+                        return false;
+                    }
+                });
+        getDecor().invalidate();
+    }
+
     private void requestLayoutForSharedElements() {
         int numSharedElements = mSharedElements.size();
         for (int i = 0; i < numSharedElements; i++) {
@@ -242,9 +301,10 @@
             if (transition == null) {
                 sharedElementTransitionStarted();
             } else {
-                transition.addListener(new Transition.TransitionListenerAdapter() {
+                transition.addListener(new ContinueTransitionListener() {
                     @Override
                     public void onTransitionStart(Transition transition) {
+                        super.onTransitionStart(transition);
                         transition.removeListener(this);
                         sharedElementTransitionStarted();
                     }
@@ -252,12 +312,17 @@
             }
         }
         if (transition != null) {
+            if (sharedElementTransition == null) {
+                transition.addListener(new ContinueTransitionListener());
+            }
             TransitionManager.beginDelayedTransition(getDecor(), transition);
             if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
                 mSharedElements.get(0).invalidate();
             } else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
                 mTransitioningViews.get(0).invalidate();
             }
+        } else {
+            transitionStarted();
         }
         return transition;
     }
@@ -276,7 +341,7 @@
             if (background != null) {
                 background = background.mutate();
                 mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 255);
-                mBackgroundAnimator.setDuration(FADE_BACKGROUND_DURATION_MS);
+                mBackgroundAnimator.setDuration(getFadeDuration());
                 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
@@ -299,8 +364,8 @@
     }
 
     public void stop() {
+        makeOpaque();
         mHasStopped = true;
-        mActivity = null;
         mIsCanceled = true;
         mResultReceiver = null;
         if (mBackgroundAnimator != null) {
@@ -310,7 +375,7 @@
     }
 
     private void makeOpaque() {
-        if (!mHasStopped) {
+        if (!mHasStopped && mActivity != null) {
             mActivity.convertFromTranslucent();
             mActivity = null;
         }
@@ -348,11 +413,21 @@
 
     protected void onRemoteExitTransitionComplete() {
         if (!allowOverlappingTransitions()) {
-            boolean startEnterTransition = true;
-            boolean startSharedElementTransition = false;
-            Transition transition = beginTransition(startEnterTransition,
-                    startSharedElementTransition);
-            startEnterTransition(transition);
+            startEnterTransitionOnly();
         }
     }
+
+    private void startEnterTransitionOnly() {
+        startTransition(new Runnable() {
+            @Override
+            public void run() {
+                setEpicenter();
+                boolean startEnterTransition = true;
+                boolean startSharedElementTransition = false;
+                Transition transition = beginTransition(startEnterTransition,
+                        startSharedElementTransition);
+                startEnterTransition(transition);
+            }
+        });
+    }
 }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ba1638ff..9f3dbdc 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -19,6 +19,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Intent;
+import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -27,6 +28,7 @@
 import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.view.View;
+import android.view.ViewGroupOverlay;
 import android.view.ViewTreeObserver;
 
 import java.util.ArrayList;
@@ -60,10 +62,10 @@
 
     private boolean mIsHidden;
 
-    private boolean mExitTransitionStarted;
-
     private Bundle mExitSharedElementBundle;
 
+    private ArrayList<View> mSharedElementSnapshots;
+
     public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
             ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
         super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning),
@@ -106,30 +108,83 @@
                 break;
             case MSG_SHARED_ELEMENT_DESTINATION:
                 mExitSharedElementBundle = resultData;
-                if (mExitTransitionStarted) {
-                    startSharedElementExit();
-                }
+                sharedElementExitBack();
                 break;
         }
     }
 
-    private void startSharedElementExit() {
+    private void sharedElementExitBack() {
         if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
-            Transition transition = getSharedElementExitTransition();
-            TransitionManager.beginDelayedTransition(getDecor(), transition);
-            ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
-                    mSharedElementNames);
-            setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+            startTransition(new Runnable() {
+                public void run() {
+                    startSharedElementExit();
+                }
+            });
         }
     }
 
+    private void startSharedElementExit() {
+        Transition transition = getSharedElementExitTransition();
+        final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
+                mSharedElementNames);
+        mSharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames);
+        transition.addListener(new Transition.TransitionListenerAdapter() {
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                setViewVisibility(mSharedElements, View.INVISIBLE);
+                ViewGroupOverlay overlay = getDecor().getOverlay();
+                if (mSharedElementSnapshots != null) {
+                    for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
+                        overlay.add(mSharedElementSnapshots.get(i));
+                    }
+                }
+            }
+        });
+        getDecor().getViewTreeObserver()
+                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+                        setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+                        return true;
+                    }
+                });
+        TransitionManager.beginDelayedTransition(getDecor(), transition);
+        getDecor().invalidate();
+    }
+
+    private static ArrayList<View> copySnapshots(ArrayList<View> snapshots) {
+        ArrayList<View> copy = new ArrayList<View>(snapshots.size());
+        for (int i = 0; i < snapshots.size(); i++) {
+            View view = snapshots.get(i);
+            View viewCopy = new View(view.getContext());
+            viewCopy.setBackground(view.getBackground());
+            copy.add(viewCopy);
+        }
+        return copy;
+    }
+
     private void hideSharedElements() {
-        setViewVisibility(mSharedElements, View.INVISIBLE);
+        if (!mIsHidden) {
+            setViewVisibility(mSharedElements, View.INVISIBLE);
+        }
+        if (mSharedElementSnapshots != null) {
+            ViewGroupOverlay overlay = getDecor().getOverlay();
+            for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
+                overlay.remove(mSharedElementSnapshots.get(i));
+            }
+            mSharedElementSnapshots = null;
+        }
         finishIfNecessary();
     }
 
     public void startExit() {
-        beginTransitions();
+        startTransition(new Runnable() {
+            @Override
+            public void run() {
+                beginTransitions();
+            }
+        });
         setViewVisibility(mTransitioningViews, View.INVISIBLE);
     }
 
@@ -159,29 +214,25 @@
                 }
             }
         }, options);
+        startTransition(new Runnable() {
+            @Override
+            public void run() {
+                startExitTransition();
+            }
+        });
+    }
+
+    private void startExitTransition() {
         Transition sharedElementTransition = mSharedElements.isEmpty()
                 ? null : getSharedElementTransition();
         if (sharedElementTransition == null) {
             sharedElementTransitionComplete();
         }
-        Transition transition = mergeTransitions(sharedElementTransition, getExitTransition());
-        if (transition == null) {
-            mExitTransitionStarted = true;
-        } else {
+        Transition transition = mergeTransitions(sharedElementTransition,
+                getExitTransition());
+        if (transition != null) {
             TransitionManager.beginDelayedTransition(getDecor(), transition);
             setViewVisibility(mTransitioningViews, View.INVISIBLE);
-            getDecor().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                @Override
-                public boolean onPreDraw() {
-                    getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
-                    mExitTransitionStarted = true;
-                    if (mExitSharedElementBundle != null) {
-                        startSharedElementExit();
-                    }
-                    notifyComplete();
-                    return true;
-                }
-            });
         }
     }
 
@@ -199,7 +250,7 @@
                     }
                 }
             });
-            mBackgroundAnimator.setDuration(FADE_BACKGROUND_DURATION_MS);
+            mBackgroundAnimator.setDuration(getFadeDuration());
             mBackgroundAnimator.start();
         }
     }
@@ -212,7 +263,7 @@
         if (viewsTransition == null) {
             exitTransitionComplete();
         } else {
-            viewsTransition.addListener(new Transition.TransitionListenerAdapter() {
+            viewsTransition.addListener(new ContinueTransitionListener() {
                 @Override
                 public void onTransitionEnd(Transition transition) {
                     exitTransitionComplete();
@@ -238,7 +289,7 @@
         if (sharedElementTransition == null) {
             sharedElementTransitionComplete();
         } else {
-            sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+            sharedElementTransition.addListener(new ContinueTransitionListener() {
                 @Override
                 public void onTransitionEnd(Transition transition) {
                     sharedElementTransitionComplete();
@@ -257,7 +308,6 @@
         Transition viewsTransition = getExitTransition();
 
         Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
-        mExitTransitionStarted = true;
         if (transition != null) {
             TransitionManager.beginDelayedTransition(getDecor(), transition);
         }
@@ -269,15 +319,31 @@
     }
 
     protected boolean isReadyToNotify() {
-        return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady
-                && mExitTransitionStarted;
+        return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
     }
 
     private void sharedElementTransitionComplete() {
-        mSharedElementBundle = captureSharedElementState();
+        mSharedElementBundle = mExitSharedElementBundle == null
+                ? captureSharedElementState() : captureExitSharedElementsState();
         notifyComplete();
     }
 
+    private Bundle captureExitSharedElementsState() {
+        Bundle bundle = new Bundle();
+        Rect bounds = new Rect();
+        for (int i = 0; i < mSharedElementNames.size(); i++) {
+            String name = mSharedElementNames.get(i);
+            Bundle sharedElementState = mExitSharedElementBundle.getBundle(name);
+            if (sharedElementState != null) {
+                bundle.putBundle(name, sharedElementState);
+            } else {
+                View view = mSharedElements.get(i);
+                captureSharedElementState(view, name, bundle, bounds);
+            }
+        }
+        return bundle;
+    }
+
     protected void notifyComplete() {
         if (isReadyToNotify()) {
             if (!mSharedElementNotified) {
@@ -294,8 +360,7 @@
     }
 
     private void finishIfNecessary() {
-        if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty()
-                || mSharedElements.get(0).getVisibility() == View.INVISIBLE)) {
+        if (mIsReturning && mExitNotified && mActivity != null && mSharedElementSnapshots == null) {
             mActivity.finish();
             mActivity.overridePendingTransition(0, 0);
             mActivity = null;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 76f9d97..b8f1962 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1494,7 +1494,7 @@
                 return false;
             }
             final BackStackRecord bss = mBackStack.remove(last);
-            bss.popFromBackStack(true);
+            bss.popFromBackStack(true, null);
             reportBackStackChanged();
         } else {
             int index = -1;
@@ -1538,9 +1538,10 @@
                 states.add(mBackStack.remove(i));
             }
             final int LAST = states.size()-1;
+            BackStackRecord.TransitionState state = null;
             for (int i=0; i<=LAST; i++) {
                 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
-                states.get(i).popFromBackStack(i == LAST);
+                state = states.get(i).popFromBackStack(i == LAST, state);
             }
             reportBackStackChanged();
         }
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 6e99899..7479ecd 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -1,5 +1,8 @@
 package android.app;
 
+import android.util.Pair;
+import android.view.View;
+
 /**
  * API for performing a set of Fragment operations.
  *
@@ -169,6 +172,36 @@
     public abstract FragmentTransaction setTransition(int transit);
 
     /**
+     * Set a {@link android.transition.Transition} resource id to use with this transaction.
+     * <var>transitionId</var> will be played for fragments when going forward and when popping
+     * the back stack.
+     * @param sceneRootId The ID of the element acting as the scene root for the transition.
+     *                    This should be a ViewGroup containing all Fragments in the transaction.
+     * @param transitionId The resource ID for the Transition used during the Fragment transaction.
+     */
+    public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId);
+
+    /**
+     * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden
+     * Fragment to a View from a shown or added Fragment.
+     * <var>sharedElement</var> must have a unique viewName in the View hierarchy.
+     * @param sharedElement A View in a disappearing Fragment to match with a View in an
+     *                      appearing Fragment.
+     * @param name The viewName for a View in an appearing Fragment to match to the shared
+     *             element.
+     */
+    public abstract FragmentTransaction setSharedElement(View sharedElement, String name);
+
+    /**
+     * Used with {@link #setCustomTransition(int, int)} to map multiple Views from removed or hidden
+     * Fragments to a Views from a shown or added Fragments. Views in
+     * <var>sharedElements</var> must have unique viewNames in the View hierarchy.
+     * @param sharedElements Pairs of Views in disappearing Fragments to viewNames in
+     *                       appearing Fragments.
+     */
+    public abstract FragmentTransaction setSharedElements(Pair<View, String>... sharedElements);
+
+    /**
      * Set a custom style resource that will be used for resolving transit
      * animations.
      */
diff --git a/core/java/android/app/TaskManagerImpl.java b/core/java/android/app/JobSchedulerImpl.java
similarity index 67%
rename from core/java/android/app/TaskManagerImpl.java
rename to core/java/android/app/JobSchedulerImpl.java
index fe29fb7..09038d5 100644
--- a/core/java/android/app/TaskManagerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -17,38 +17,38 @@
 // in android.app so ContextImpl has package access
 package android.app;
 
-import android.app.task.ITaskManager;
-import android.app.task.Task;
-import android.app.task.TaskManager;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.IJobScheduler;
 import android.os.RemoteException;
 
 import java.util.List;
 
 
 /**
- * Concrete implementation of the TaskManager interface
+ * Concrete implementation of the JobScheduler interface
  * @hide 
  */
-public class TaskManagerImpl extends TaskManager {
-    ITaskManager mBinder;
+public class JobSchedulerImpl extends JobScheduler {
+    IJobScheduler mBinder;
 
-    /* package */ TaskManagerImpl(ITaskManager binder) {
+    /* package */ JobSchedulerImpl(IJobScheduler binder) {
         mBinder = binder;
     }
 
     @Override
-    public int schedule(Task task) {
+    public int schedule(JobInfo job) {
         try {
-            return mBinder.schedule(task);
+            return mBinder.schedule(job);
         } catch (RemoteException e) {
-            return TaskManager.RESULT_FAILURE;
+            return JobScheduler.RESULT_FAILURE;
         }
     }
 
     @Override
-    public void cancel(int taskId) {
+    public void cancel(int jobId) {
         try {
-            mBinder.cancel(taskId);
+            mBinder.cancel(jobId);
         } catch (RemoteException e) {}
 
     }
@@ -62,9 +62,9 @@
     }
 
     @Override
-    public List<Task> getAllPendingTasks() {
+    public List<JobInfo> getAllPendingJobs() {
         try {
-            return mBinder.getAllPendingTasks();
+            return mBinder.getAllPendingJobs();
         } catch (RemoteException e) {
             return null;
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 276f936..b94fd41 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2867,16 +2867,16 @@
     /**
      * Helper class for generating large-format notifications that include a large image attachment.
      *
-     * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+     * Here's how you'd set the <code>BigPictureStyle</code> on a notification:
      * <pre class="prettyprint">
-     * Notification noti = new Notification.BigPictureStyle(
-     *      new Notification.Builder()
-     *         .setContentTitle(&quot;New photo from &quot; + sender.toString())
-     *         .setContentText(subject)
-     *         .setSmallIcon(R.drawable.new_post)
-     *         .setLargeIcon(aBitmap))
-     *      .bigPicture(aBigBitmap)
-     *      .build();
+     * Notification notif = new Notification.Builder(mContext)
+     *     .setContentTitle(&quot;New photo from &quot; + sender.toString())
+     *     .setContentText(subject)
+     *     .setSmallIcon(R.drawable.new_post)
+     *     .setLargeIcon(aBitmap)
+     *     .setStyle(new Notification.BigPictureStyle()
+     *         .bigPicture(aBigBitmap))
+     *     .build();
      * </pre>
      *
      * @see Notification#bigContentView
@@ -2963,16 +2963,16 @@
     /**
      * Helper class for generating large-format notifications that include a lot of text.
      *
-     * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+     * Here's how you'd set the <code>BigTextStyle</code> on a notification:
      * <pre class="prettyprint">
-     * Notification noti = new Notification.BigTextStyle(
-     *      new Notification.Builder()
-     *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
-     *         .setContentText(subject)
-     *         .setSmallIcon(R.drawable.new_mail)
-     *         .setLargeIcon(aBitmap))
-     *      .bigText(aVeryLongString)
-     *      .build();
+     * Notification notif = new Notification.Builder(mContext)
+     *     .setContentTitle(&quot;New mail from &quot; + sender.toString())
+     *     .setContentText(subject)
+     *     .setSmallIcon(R.drawable.new_mail)
+     *     .setLargeIcon(aBitmap)
+     *     .setStyle(new Notification.BigTextStyle()
+     *         .bigText(aVeryLongString))
+     *     .build();
      * </pre>
      *
      * @see Notification#bigContentView
@@ -3057,19 +3057,19 @@
     /**
      * Helper class for generating large-format notifications that include a list of (up to 5) strings.
      *
-     * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+     * Here's how you'd set the <code>InboxStyle</code> on a notification:
      * <pre class="prettyprint">
-     * Notification noti = new Notification.InboxStyle(
-     *      new Notification.Builder()
-     *         .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
-     *         .setContentText(subject)
-     *         .setSmallIcon(R.drawable.new_mail)
-     *         .setLargeIcon(aBitmap))
-     *      .addLine(str1)
-     *      .addLine(str2)
-     *      .setContentTitle("")
-     *      .setSummaryText(&quot;+3 more&quot;)
-     *      .build();
+     * Notification notif = new Notification.Builder(mContext)
+     *     .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
+     *     .setContentText(subject)
+     *     .setSmallIcon(R.drawable.new_mail)
+     *     .setLargeIcon(aBitmap)
+     *     .setStyle(new Notification.InboxStyle()
+     *         .addLine(str1)
+     *         .addLine(str2)
+     *         .setContentTitle(&quot;&quot;)
+     *         .setSummaryText(&quot;+3 more&quot;))
+     *     .build();
      * </pre>
      *
      * @see Notification#bigContentView
@@ -3619,14 +3619,16 @@
          *         .build();</pre>
          *
          * <p>The activity to launch needs to allow embedding, must be exported, and
-         * should have an empty task affinity.
+         * should have an empty task affinity. It is also recommended to use the device
+         * default light theme.
          *
          * <p>Example AndroidManifest.xml entry:
          * <pre class="prettyprint">
          * &lt;activity android:name=&quot;com.example.MyDisplayActivity&quot;
          *     android:exported=&quot;true&quot;
          *     android:allowEmbedded=&quot;true&quot;
-         *     android:taskAffinity=&quot;&quot; /&gt;</pre>
+         *     android:taskAffinity=&quot;&quot;
+         *     android:theme=&quot;@android:style/Theme.DeviceDefault.Light&quot; /&gt;</pre>
          *
          * @param intent the {@link PendingIntent} for an activity
          * @return this object for method chaining
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 85e970c..0d947217 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -293,7 +293,7 @@
 
         IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
                 IVoiceInteractorCallback callback) throws RemoteException {
-            return interactor.startConfirmation(packageName, callback, mCommand, mArgs);
+            return interactor.startCommand(packageName, callback, mCommand, mArgs);
         }
    }
 
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 1015514..45a2625 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -222,6 +222,12 @@
      * Called after the administrator is first enabled, as a result of
      * receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}.  At this point you
      * can use {@link DevicePolicyManager} to set your desired policies.
+     *
+     * <p> If the admin is activated by a device owner, then the intent
+     * may contain private extras that are relevant to user setup.
+     * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
+     *      ComponentName, Intent)}
+     *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 04be028..e80c761 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2111,6 +2111,41 @@
     }
 
     /**
+     * Called by a device owner to create a user with the specified name. The UserHandle returned
+     * by this method should not be persisted as user handles are recycled as users are removed and
+     * created. If you need to persist an identifier for this user, use
+     * {@link UserManager#getSerialNumberForUser}.  The new user will be started in the background
+     * immediately.
+     *
+     * <p> profileOwnerComponent is the {@link DeviceAdminReceiver} to be the profile owner as well
+     * as registered as an active admin on the new user.  The profile owner package will be
+     * installed on the new user if it already is installed on the device.
+     *
+     * <p>If the optionalInitializeData is not null, then the extras will be passed to the
+     * profileOwnerComponent when onEnable is called.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param name the user's name
+     * @param ownerName the human readable name of the organisation associated with this DPM.
+     * @param profileOwnerComponent The {@link DeviceAdminReceiver} that will be an active admin on
+     *      the user.
+     * @param adminExtras Extras that will be passed to onEnable of the admin receiver
+     *      on the new user.
+     * @see UserHandle
+     * @return the UserHandle object for the created user, or null if the user could not be created.
+     */
+    public UserHandle createAndInitializeUser(ComponentName admin, String name, String ownerName,
+            ComponentName profileOwnerComponent, Bundle adminExtras) {
+        try {
+            return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
+                    adminExtras);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not create a user", re);
+        }
+        return null;
+    }
+
+    /**
      * Called by a device owner to remove a user and all associated data. The primary user can
      * not be removed.
      *
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f8df780b..a1caa21 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -136,6 +136,7 @@
     boolean isApplicationBlocked(in ComponentName admin, in String packageName);
 
     UserHandle createUser(in ComponentName who, in String name);
+    UserHandle createAndInitializeUser(in ComponentName who, in String name, in String profileOwnerName, in ComponentName profileOwnerComponent, in Bundle adminExtras);
     boolean removeUser(in ComponentName who, in UserHandle userHandle);
 
     void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 46f082e..706ef04 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -228,19 +228,35 @@
     }
 
     /**
-     * Get the package name of the next application with data in the backup store.
+     * Get the package name of the next application with data in the backup store, plus
+     * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+     * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
      *
-     * @return The name of one of the packages supplied to {@link #startRestore},
-     *   or "" (the empty string) if no more backup data is available,
-     *   or null if an error occurred (the restore should be aborted and rescheduled).
+     * <p>If the package name in the returned RestoreDescription object is the singleton
+     * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+     * in the current restore session: all packages described in startRestore() have been
+     * processed.
+     *
+     * <p>If this method returns {@code null}, it means that a transport-level error has
+     * occurred and the entire restore operation should be abandoned.
+     *
+     * @return A RestoreDescription object containing the name of one of the packages
+     *   supplied to {@link #startRestore} plus an indicator of the data type of that
+     *   restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+     *   no more packages can be restored in this session; or {@code null} to indicate
+     *   a transport-level error.
      */
-    public String nextRestorePackage() {
+    public RestoreDescription nextRestorePackage() {
         return null;
     }
 
     /**
-     * Get the data for the application returned by {@link #nextRestorePackage}.
-     * @param data An open, writable file into which the backup data should be stored.
+     * Get the data for the application returned by {@link #nextRestorePackage}, if that
+     * method reported {@link RestoreDescription#TYPE_KEY_VALUE} as its delivery type.
+     * If the package has only TYPE_FULL_STREAM data, then this method will return an
+     * error.
+     *
+     * @param data An open, writable file into which the key/value backup data should be stored.
      * @return the same error codes as {@link #startRestore}.
      */
     public int getRestoreData(ParcelFileDescriptor outFd) {
@@ -328,6 +344,59 @@
         return BackupTransport.TRANSPORT_ERROR;
     }
 
+    // ------------------------------------------------------------------------------------
+    // Full restore interfaces
+
+    /**
+     * Ask the transport to provide data for the "current" package being restored.  This
+     * is the package that was just reported by {@link #nextRestorePackage()} as having
+     * {@link RestoreDescription#TYPE_FULL_STREAM} data.
+     *
+     * The transport writes some data to the socket supplied to this call, and returns
+     * the number of bytes written.  The system will then read that many bytes and
+     * stream them to the application's agent for restore, then will call this method again
+     * to receive the next chunk of the archive.  This sequence will be repeated until the
+     * transport returns zero indicating that all of the package's data has been delivered
+     * (or returns a negative value indicating some sort of hard error condition at the
+     * transport level).
+     *
+     * <p>After this method returns zero, the system will then call
+     * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+     * application, and the sequence begins again.
+     *
+     * <p>The transport should always close this socket when returning from this method.
+     * Do not cache this socket across multiple calls or you may leak file descriptors.
+     *
+     * @param socket The file descriptor that the transport will use for delivering the
+     *    streamed archive.  The transport must close this socket in all cases when returning
+     *    from this method.
+     * @return 0 when no more data for the current package is available.  A positive value
+     *    indicates the presence of that many bytes to be delivered to the app.  Any negative
+     *    return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+     *    indicating a fatal error condition that precludes further restore operations
+     *    on the current dataset.
+     */
+    public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+        return 0;
+    }
+
+    /**
+     * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+     * data for restore, it will invoke this method to tell the transport that it should
+     * abandon the data download for the current package.  The OS will then either call
+     * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+     * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+     * operation.
+     *
+     * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+     *    current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+     *    transport-level failure.  If the transport reports an error here, the entire restore
+     *    operation will immediately be finished with no further attempts to restore app data.
+     */
+    public int abortFullRestore() {
+        return BackupTransport.TRANSPORT_OK;
+    }
+
     /**
      * Bridge between the actual IBackupTransport implementation and the stable API.  If the
      * binder interface needs to change, we use this layer to translate so that we can
@@ -398,7 +467,7 @@
         }
 
         @Override
-        public String nextRestorePackage() throws RemoteException {
+        public RestoreDescription nextRestorePackage() throws RemoteException {
             return BackupTransport.this.nextRestorePackage();
         }
 
@@ -411,5 +480,30 @@
         public void finishRestore() throws RemoteException {
             BackupTransport.this.finishRestore();
         }
+
+        @Override
+        public long requestFullBackupTime() throws RemoteException {
+            return BackupTransport.this.requestFullBackupTime();
+        }
+
+        @Override
+        public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException {
+            return BackupTransport.this.performFullBackup(targetPackage, socket);
+        }
+
+        @Override
+        public int sendBackupData(int numBytes) throws RemoteException {
+            return BackupTransport.this.sendBackupData(numBytes);
+        }
+
+        @Override
+        public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+            return BackupTransport.this.getNextFullRestoreDataChunk(socket);
+        }
+
+        @Override
+        public int abortFullRestore() {
+            return BackupTransport.this.abortFullRestore();
+        }
     }
 }
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index c629a2e..72bc4f0 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -168,7 +168,15 @@
      */
     void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
             boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,
-            in String[] packageNames);
+            boolean doCompress, in String[] packageNames);
+
+    /**
+     * Perform a full-dataset backup of the given applications via the currently active
+     * transport.
+     *
+     * @param packageNames The package names of the apps whose data are to be backed up.
+     */
+    void fullTransportBackup(in String[] packageNames);
 
     /**
      * Restore device content from the data stream passed through the given socket.  The
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/backup/RestoreDescription.aidl
similarity index 90%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/app/backup/RestoreDescription.aidl
index 1f25439..9cbea78 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/app/backup/RestoreDescription.aidl
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.app.backup;
 
-parcelable Task;
- 
\ No newline at end of file
+parcelable RestoreDescription;
diff --git a/core/java/android/app/backup/RestoreDescription.java b/core/java/android/app/backup/RestoreDescription.java
new file mode 100644
index 0000000..0fb4355
--- /dev/null
+++ b/core/java/android/app/backup/RestoreDescription.java
@@ -0,0 +1,101 @@
+/*
+ * 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.backup;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Description of the available restore data for a given package.  Returned by a
+ * BackupTransport in response to a request about the next available restorable
+ * package.
+ *
+ * @see BackupTransport#nextRestorePackage()
+ *
+ * @hide
+ */
+public class RestoreDescription implements Parcelable {
+    private final String mPackageName;
+    private final int mDataType;
+
+    private static final String NO_MORE_PACKAGES_SENTINEL = "";
+
+    /**
+     * Return this constant RestoreDescription from BackupTransport.nextRestorePackage()
+     * to indicate that no more package data is available in the current restore operation.
+     */
+    public static final RestoreDescription NO_MORE_PACKAGES =
+            new RestoreDescription(NO_MORE_PACKAGES_SENTINEL, 0);
+
+    // ---------------------------------------
+    // Data type identifiers
+
+    /** This package's restore data is an original-style key/value dataset */
+    public static final int TYPE_KEY_VALUE = 1;
+
+    /** This package's restore data is a tarball-type full data stream */
+    public static final int TYPE_FULL_STREAM = 2;
+
+    // ---------------------------------------
+    // API
+
+    public RestoreDescription(String packageName, int dataType) {
+        mPackageName = packageName;
+        mDataType = dataType;
+    }
+
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    public int getDataType() {
+        return mDataType;
+    }
+
+    // ---------------------------------------
+    // Parcelable implementation - not used by transport
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mPackageName);
+        out.writeInt(mDataType);
+    }
+
+    public static final Parcelable.Creator<RestoreDescription> CREATOR
+            = new Parcelable.Creator<RestoreDescription>() {
+        public RestoreDescription createFromParcel(Parcel in) {
+            final RestoreDescription unparceled = new RestoreDescription(in);
+            return (NO_MORE_PACKAGES_SENTINEL.equals(unparceled.mPackageName))
+                    ? NO_MORE_PACKAGES
+                    : unparceled;
+        }
+
+        public RestoreDescription[] newArray(int size) {
+            return new RestoreDescription[size];
+        }
+    };
+
+    private RestoreDescription(Parcel in) {
+        mPackageName = in.readString();
+        mDataType = in.readInt();
+    }
+}
diff --git a/core/java/android/app/job/IJobCallback.aidl b/core/java/android/app/job/IJobCallback.aidl
new file mode 100644
index 0000000..2d3948f
--- /dev/null
+++ b/core/java/android/app/job/IJobCallback.aidl
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.job;
+
+/**
+ * The server side of the JobScheduler IPC protocols.  The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which Job Service instance is reporting.
+ *
+ * {@hide}
+ */
+interface IJobCallback {
+    /**
+     * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
+     *
+     * @param jobId Unique integer used to identify this job.
+     * @param ongoing True to indicate that the client is processing the job. False if the job is
+     * complete
+     */
+    void acknowledgeStartMessage(int jobId, boolean ongoing);
+    /**
+     * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
+     *
+     * @param jobId Unique integer used to identify this job.
+     * @param reschedule Whether or not to reschedule this job.
+     */
+    void acknowledgeStopMessage(int jobId, boolean reschedule);
+    /*
+     * Tell the job manager that the client is done with its execution, so that it can go on to
+     * the next one and stop attributing wakelock time to us etc.
+     *
+     * @param jobId Unique integer used to identify this job.
+     * @param reschedule Whether or not to reschedule this job.
+     */
+    void jobFinished(int jobId, boolean reschedule);
+}
diff --git a/core/java/android/app/task/ITaskManager.aidl b/core/java/android/app/job/IJobScheduler.aidl
similarity index 71%
rename from core/java/android/app/task/ITaskManager.aidl
rename to core/java/android/app/job/IJobScheduler.aidl
index b56c78a..f1258ae 100644
--- a/core/java/android/app/task/ITaskManager.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.app.job;
 
-import android.app.task.Task;
+import android.app.job.JobInfo;
 
  /**
-  * IPC interface that supports the app-facing {@link #TaskManager} api.
+  * IPC interface that supports the app-facing {@link #JobScheduler} api.
   * {@hide}
   */
-interface ITaskManager {
-    int schedule(in Task task);
-    void cancel(int taskId);
+interface IJobScheduler {
+    int schedule(in JobInfo job);
+    void cancel(int jobId);
     void cancelAll();
-    List<Task> getAllPendingTasks();
+    List<JobInfo> getAllPendingJobs();
 }
diff --git a/core/java/android/app/task/ITaskService.aidl b/core/java/android/app/job/IJobService.aidl
similarity index 62%
rename from core/java/android/app/task/ITaskService.aidl
rename to core/java/android/app/job/IJobService.aidl
index 87b0191..63f8b81 100644
--- a/core/java/android/app/task/ITaskService.aidl
+++ b/core/java/android/app/job/IJobService.aidl
@@ -14,22 +14,19 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.app.job;
 
-import android.app.task.ITaskCallback;
-import android.app.task.TaskParams;
-
-import android.os.Bundle;
+import android.app.job.JobParameters;
 
 /**
  * Interface that the framework uses to communicate with application code that implements a
- * TaskService.  End user code does not implement this interface directly; instead, the app's
- * service implementation will extend android.app.task.TaskService.
+ * JobService.  End user code does not implement this interface directly; instead, the app's
+ * service implementation will extend android.app.job.JobService.
  * {@hide}
  */
-oneway interface ITaskService {
-    /** Begin execution of application's task. */
-    void startTask(in TaskParams taskParams);
+oneway interface IJobService {
+    /** Begin execution of application's job. */
+    void startJob(in JobParameters jobParams);
     /** Stop execution of application's task. */
-    void stopTask(in TaskParams taskParams);
+    void stopJob(in JobParameters jobParams);
 }
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/job/JobInfo.aidl
similarity index 92%
rename from core/java/android/app/task/Task.aidl
rename to core/java/android/app/job/JobInfo.aidl
index 1f25439..7b198a8 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/app/job/JobInfo.aidl
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.app.job;
 
-parcelable Task;
- 
\ No newline at end of file
+parcelable JobInfo;
diff --git a/core/java/android/app/task/Task.java b/core/java/android/app/job/JobInfo.java
similarity index 74%
rename from core/java/android/app/task/Task.java
rename to core/java/android/app/job/JobInfo.java
index 0e660b3..a22e4cd 100644
--- a/core/java/android/app/task/Task.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.app.task;
+package android.app.job;
 
 import android.content.ComponentName;
 import android.os.Bundle;
@@ -23,22 +23,22 @@
 import android.os.PersistableBundle;
 
 /**
- * Container of data passed to the {@link android.app.task.TaskManager} fully encapsulating the
+ * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
  * parameters required to schedule work against the calling application. These are constructed
- * using the {@link Task.Builder}.
+ * using the {@link JobInfo.Builder}.
  */
-public class Task implements Parcelable {
+public class JobInfo implements Parcelable {
     public interface NetworkType {
         /** Default. */
         public final int NONE = 0;
-        /** This task requires network connectivity. */
+        /** This job requires network connectivity. */
         public final int ANY = 1;
-        /** This task requires network connectivity that is unmetered. */
+        /** This job requires network connectivity that is unmetered. */
         public final int UNMETERED = 2;
     }
 
     /**
-     * Amount of backoff a task has initially by default, in milliseconds.
+     * Amount of backoff a job has initially by default, in milliseconds.
      * @hide.
      */
     public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 5000L;
@@ -63,7 +63,7 @@
         public final int EXPONENTIAL = 1;
     }
 
-    private final int taskId;
+    private final int jobId;
     // TODO: Change this to use PersistableBundle when that lands in master.
     private final PersistableBundle extras;
     private final ComponentName service;
@@ -80,10 +80,10 @@
     private final int backoffPolicy;
 
     /**
-     * Unique task id associated with this class. This is assigned to your task by the scheduler.
+     * Unique job id associated with this class. This is assigned to your job by the scheduler.
      */
     public int getId() {
-        return taskId;
+        return jobId;
     }
 
     /**
@@ -94,43 +94,43 @@
     }
 
     /**
-     * Name of the service endpoint that will be called back into by the TaskManager.
+     * Name of the service endpoint that will be called back into by the JobScheduler.
      */
     public ComponentName getService() {
         return service;
     }
 
     /**
-     * Whether this task needs the device to be plugged in.
+     * Whether this job needs the device to be plugged in.
      */
     public boolean isRequireCharging() {
         return requireCharging;
     }
 
     /**
-     * Whether this task needs the device to be in an Idle maintenance window.
+     * Whether this job needs the device to be in an Idle maintenance window.
      */
     public boolean isRequireDeviceIdle() {
         return requireDeviceIdle;
     }
 
     /**
-     * See {@link android.app.task.Task.NetworkType} for a description of this value.
+     * See {@link android.app.job.JobInfo.NetworkType} for a description of this value.
      */
     public int getNetworkCapabilities() {
         return networkCapabilities;
     }
 
     /**
-     * Set for a task that does not recur periodically, to specify a delay after which the task
-     * will be eligible for execution. This value is not set if the task recurs periodically.
+     * Set for a job that does not recur periodically, to specify a delay after which the job
+     * will be eligible for execution. This value is not set if the job recurs periodically.
      */
     public long getMinLatencyMillis() {
         return minLatencyMillis;
     }
 
     /**
-     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
      * periodically.
      */
     public long getMaxExecutionDelayMillis() {
@@ -138,23 +138,23 @@
     }
 
     /**
-     * Track whether this task will repeat with a given period.
+     * Track whether this job will repeat with a given period.
      */
     public boolean isPeriodic() {
         return isPeriodic;
     }
 
     /**
-     * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
-     * task does not recur periodically.
+     * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
+     * job does not recur periodically.
      */
     public long getIntervalMillis() {
         return intervalMillis;
     }
 
     /**
-     * The amount of time the TaskManager will wait before rescheduling a failed task. This value
-     * will be increased depending on the backoff policy specified at task creation time. Defaults
+     * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
+     * will be increased depending on the backoff policy specified at job creation time. Defaults
      * to 5 seconds.
      */
     public long getInitialBackoffMillis() {
@@ -162,7 +162,7 @@
     }
 
     /**
-     * See {@link android.app.task.Task.BackoffPolicy} for an explanation of the values this field
+     * See {@link android.app.job.JobInfo.BackoffPolicy} for an explanation of the values this field
      * can take. This defaults to exponential.
      */
     public int getBackoffPolicy() {
@@ -187,8 +187,8 @@
         return hasLateConstraint;
     }
 
-    private Task(Parcel in) {
-        taskId = in.readInt();
+    private JobInfo(Parcel in) {
+        jobId = in.readInt();
         extras = in.readPersistableBundle();
         service = in.readParcelable(null);
         requireCharging = in.readInt() == 1;
@@ -204,10 +204,10 @@
         hasLateConstraint = in.readInt() == 1;
     }
 
-    private Task(Task.Builder b) {
-        taskId = b.mTaskId;
+    private JobInfo(JobInfo.Builder b) {
+        jobId = b.mJobId;
         extras = b.mExtras;
-        service = b.mTaskService;
+        service = b.mJobService;
         requireCharging = b.mRequiresCharging;
         requireDeviceIdle = b.mRequiresDeviceIdle;
         networkCapabilities = b.mNetworkCapabilities;
@@ -228,7 +228,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(taskId);
+        out.writeInt(jobId);
         out.writePersistableBundle(extras);
         out.writeParcelable(service, flags);
         out.writeInt(requireCharging ? 1 : 0);
@@ -244,23 +244,23 @@
         out.writeInt(hasLateConstraint ? 1 : 0);
     }
 
-    public static final Creator<Task> CREATOR = new Creator<Task>() {
+    public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
         @Override
-        public Task createFromParcel(Parcel in) {
-            return new Task(in);
+        public JobInfo createFromParcel(Parcel in) {
+            return new JobInfo(in);
         }
 
         @Override
-        public Task[] newArray(int size) {
-            return new Task[size];
+        public JobInfo[] newArray(int size) {
+            return new JobInfo[size];
         }
     };
 
-    /** Builder class for constructing {@link Task} objects. */
+    /** Builder class for constructing {@link JobInfo} objects. */
     public static final class Builder {
-        private int mTaskId;
+        private int mJobId;
         private PersistableBundle mExtras = PersistableBundle.EMPTY;
-        private ComponentName mTaskService;
+        private ComponentName mJobService;
         // Requirements.
         private boolean mRequiresCharging;
         private boolean mRequiresDeviceIdle;
@@ -280,15 +280,15 @@
         private boolean mBackoffPolicySet = false;
 
         /**
-         * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
-         *               tasks created with the same taskId, will update the pre-existing task with
+         * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
+         *               jobs created with the same jobId, will update the pre-existing job with
          *               the same id.
-         * @param taskService The endpoint that you implement that will receive the callback from the
-         *            TaskManager.
+         * @param jobService The endpoint that you implement that will receive the callback from the
+         *            JobScheduler.
          */
-        public Builder(int taskId, ComponentName taskService) {
-            mTaskService = taskService;
-            mTaskId = taskId;
+        public Builder(int jobId, ComponentName jobService) {
+            mJobService = jobService;
+            mJobId = jobId;
         }
 
         /**
@@ -302,10 +302,10 @@
 
         /**
          * Set some description of the kind of network capabilities you would like to have. This
-         * will be a parameter defined in {@link android.app.task.Task.NetworkType}.
+         * will be a parameter defined in {@link android.app.job.JobInfo.NetworkType}.
          * Not calling this function means the network is not necessary.
          * Bear in mind that calling this function defines network as a strict requirement for your
-         * task if the network requested is not available your task will never run. See
+         * job if the network requested is not available your job will never run. See
          * {@link #setOverrideDeadline(long)} to change this behaviour.
          */
         public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
@@ -313,10 +313,10 @@
             return this;
         }
 
-        /*
-         * Specify that to run this task, the device needs to be plugged in. This defaults to
+        /**
+         * Specify that to run this job, the device needs to be plugged in. This defaults to
          * false.
-         * @param requireCharging Whether or not the device is plugged in.
+         * @param requiresCharging Whether or not the device is plugged in.
          */
         public Builder setRequiresCharging(boolean requiresCharging) {
             mRequiresCharging = requiresCharging;
@@ -324,11 +324,11 @@
         }
 
         /**
-         * Specify that to run, the task needs the device to be in idle mode. This defaults to
+         * Specify that to run, the job needs the device to be in idle mode. This defaults to
          * false.
          * <p>Idle mode is a loose definition provided by the system, which means that the device
          * is not in use, and has not been in use for some time. As such, it is a good time to
-         * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+         * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
          * to your application, and surfaced to the user in battery stats.</p>
          * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
          *                           window.
@@ -339,17 +339,17 @@
         }
 
         /**
-         * Specify that this task should recur with the provided interval, not more than once per
-         * period. You have no control over when within this interval this task will be executed,
+         * Specify that this job should recur with the provided interval, not more than once per
+         * period. You have no control over when within this interval this job will be executed,
          * only the guarantee that it will be executed at most once within this interval.
-         * A periodic task will be repeated until the phone is turned off, however it will only be
+         * A periodic job will be repeated until the phone is turned off, however it will only be
          * persisted beyond boot if the client app has declared the
          * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
-         * periodic tasks without this permission, they simply will cease to exist after the phone
+         * periodic jobs without this permission, they simply will cease to exist after the phone
          * restarts.
          * Setting this function on the builder with {@link #setMinimumLatency(long)} or
          * {@link #setOverrideDeadline(long)} will result in an error.
-         * @param intervalMillis Millisecond interval for which this task will repeat.
+         * @param intervalMillis Millisecond interval for which this job will repeat.
          */
         public Builder setPeriodic(long intervalMillis) {
             mIsPeriodic = true;
@@ -359,11 +359,11 @@
         }
 
         /**
-         * Specify that this task should be delayed by the provided amount of time.
-         * Because it doesn't make sense setting this property on a periodic task, doing so will
+         * Specify that this job should be delayed by the provided amount of time.
+         * Because it doesn't make sense setting this property on a periodic job, doing so will
          * throw an {@link java.lang.IllegalArgumentException} when
-         * {@link android.app.task.Task.Builder#build()} is called.
-         * @param minLatencyMillis Milliseconds before which this task will not be considered for
+         * {@link android.app.job.JobInfo.Builder#build()} is called.
+         * @param minLatencyMillis Milliseconds before which this job will not be considered for
          *                         execution.
          */
         public Builder setMinimumLatency(long minLatencyMillis) {
@@ -373,11 +373,11 @@
         }
 
         /**
-         * Set deadline which is the maximum scheduling latency. The task will be run by this
+         * Set deadline which is the maximum scheduling latency. The job will be run by this
          * deadline even if other requirements are not met. Because it doesn't make sense setting
-         * this property on a periodic task, doing so will throw an
+         * this property on a periodic job, doing so will throw an
          * {@link java.lang.IllegalArgumentException} when
-         * {@link android.app.task.Task.Builder#build()} is called.
+         * {@link android.app.job.JobInfo.Builder#build()} is called.
          */
         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
@@ -389,13 +389,13 @@
          * Set up the back-off/retry policy.
          * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
          * 1hr.
-         * Note that trying to set a backoff criteria for a task with
+         * Note that trying to set a backoff criteria for a job with
          * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
-         * This is because back-off typically does not make sense for these types of tasks. See
-         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
-         * for more description of the return value for the case of a task executing while in idle
+         * This is because back-off typically does not make sense for these types of jobs. See
+         * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
+         * for more description of the return value for the case of a job executing while in idle
          * mode.
-         * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+         * @param initialBackoffMillis Millisecond time interval to wait initially when job has
          *                             failed.
          * @param backoffPolicy is one of {@link BackoffPolicy}
          */
@@ -407,25 +407,25 @@
         }
 
         /**
-         * @return The task object to hand to the TaskManager. This object is immutable.
+         * @return The job object to hand to the JobScheduler. This object is immutable.
          */
-        public Task build() {
+        public JobInfo build() {
             mExtras = new PersistableBundle(mExtras);  // Make our own copy.
-            // Check that a deadline was not set on a periodic task.
+            // Check that a deadline was not set on a periodic job.
             if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
                 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
-                        "periodic task.");
+                        "periodic job.");
             }
             if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
                 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
-                        "periodic task");
+                        "periodic job");
             }
             if (mBackoffPolicySet && mRequiresDeviceIdle) {
-                throw new IllegalArgumentException("An idle mode task will not respect any" +
+                throw new IllegalArgumentException("An idle mode job will not respect any" +
                         " back-off policy, so calling setBackoffCriteria with" +
                         " setRequiresDeviceIdle is an error.");
             }
-            return new Task(this);
+            return new JobInfo(this);
         }
     }
 
diff --git a/core/java/android/app/task/TaskParams.aidl b/core/java/android/app/job/JobParameters.aidl
similarity index 91%
rename from core/java/android/app/task/TaskParams.aidl
rename to core/java/android/app/job/JobParameters.aidl
index 9b25855..e7551b9 100644
--- a/core/java/android/app/task/TaskParams.aidl
+++ b/core/java/android/app/job/JobParameters.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.app.job;
 
-parcelable TaskParams;
\ No newline at end of file
+parcelable JobParameters;
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
new file mode 100644
index 0000000..724856a
--- /dev/null
+++ b/core/java/android/app/job/JobParameters.java
@@ -0,0 +1,93 @@
+/*
+ * 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.job;
+
+import android.app.job.IJobCallback;
+import android.app.job.IJobCallback.Stub;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+
+/**
+ * Contains the parameters used to configure/identify your job. You do not create this object
+ * yourself, instead it is handed in to your application by the System.
+ */
+public class JobParameters implements Parcelable {
+
+    private final int jobId;
+    private final PersistableBundle extras;
+    private final IBinder callback;
+
+    /** @hide */
+    public JobParameters(int jobId, PersistableBundle extras, IBinder callback) {
+        this.jobId = jobId;
+        this.extras = extras;
+        this.callback = callback;
+    }
+
+    /**
+     * @return The unique id of this job, specified at creation time.
+     */
+    public int getJobId() {
+        return jobId;
+    }
+
+    /**
+     * @return The extras you passed in when constructing this job with
+     * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
+     * never be null. If you did not set any extras this will be an empty bundle.
+     */
+    public PersistableBundle getExtras() {
+        return extras;
+    }
+
+    /** @hide */
+    public IJobCallback getCallback() {
+        return IJobCallback.Stub.asInterface(callback);
+    }
+
+    private JobParameters(Parcel in) {
+        jobId = in.readInt();
+        extras = in.readPersistableBundle();
+        callback = in.readStrongBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(jobId);
+        dest.writePersistableBundle(extras);
+        dest.writeStrongBinder(callback);
+    }
+
+    public static final Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
+        @Override
+        public JobParameters createFromParcel(Parcel in) {
+            return new JobParameters(in);
+        }
+
+        @Override
+        public JobParameters[] newArray(int size) {
+            return new JobParameters[size];
+        }
+    };
+}
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
new file mode 100644
index 0000000..7fe192c
--- /dev/null
+++ b/core/java/android/app/job/JobScheduler.java
@@ -0,0 +1,72 @@
+/*
+ * 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.job;
+
+import java.util.List;
+
+import android.content.Context;
+
+/**
+ * Class for scheduling various types of jobs with the scheduling framework on the device.
+ *
+ * <p>You do not
+ * instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)}.
+ */
+public abstract class JobScheduler {
+    /**
+     * Returned from {@link #schedule(JobInfo)} when an invalid parameter was supplied. This can occur
+     * if the run-time for your job is too short, or perhaps the system can't resolve the
+     * requisite {@link JobService} in your package.
+     */
+    public static final int RESULT_FAILURE = 0;
+    /**
+     * Returned from {@link #schedule(JobInfo)} if this application has made too many requests for
+     * work over too short a time.
+     */
+    // TODO: Determine if this is necessary.
+    public static final int RESULT_SUCCESS = 1;
+
+    /**
+     * @param job The job you wish scheduled. See
+     * {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
+     * you can schedule.
+     * @return If >0, this int returns the jobId of the successfully scheduled job.
+     * Otherwise you have to compare the return value to the error codes defined in this class.
+     */
+    public abstract int schedule(JobInfo job);
+
+    /**
+     * Cancel a job that is pending in the JobScheduler.
+     * @param jobId unique identifier for this job. Obtain this value from the jobs returned by
+     * {@link #getAllPendingJobs()}.
+     * @return
+     */
+    public abstract void cancel(int jobId);
+
+    /**
+     * Cancel all jobs that have been registered with the JobScheduler by this package.
+     */
+    public abstract void cancelAll();
+
+    /**
+     * @return a list of all the jobs registered by this package that have not yet been executed.
+     */
+    public abstract List<JobInfo> getAllPendingJobs();
+
+}
diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java
new file mode 100644
index 0000000..eea0268
--- /dev/null
+++ b/core/java/android/app/job/JobService.java
@@ -0,0 +1,260 @@
+/*
+ * 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.job;
+
+import android.app.Service;
+import android.app.job.IJobCallback;
+import android.app.job.IJobService;
+import android.app.job.IJobService.Stub;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * <p>Entry point for the callback from the {@link android.app.job.JobScheduler}.</p>
+ * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
+ * are responsible for overriding {@link JobService#onStartJob(JobParameters)}, which is where
+ * you will implement your job logic.</p>
+ * <p>This service executes each incoming job on a {@link android.os.Handler} running on your
+ * application's main thread. This means that you <b>must</b> offload your execution logic to
+ * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
+ * in blocking any future callbacks from the JobManager - specifically
+ * {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the
+ * scheduling requirements are no longer being met.</p>
+ */
+public abstract class JobService extends Service {
+    private static final String TAG = "JobService";
+
+    /**
+     * Job services must be protected with this permission:
+     *
+     * <pre class="prettyprint">
+     *     <service android:name="MyJobService"
+     *              android:permission="android.permission.BIND_JOB_SERVICE" >
+     *         ...
+     *     </service>
+     * </pre>
+     *
+     * <p>If a job service is declared in the manifest but not protected with this
+     * permission, that service will be ignored by the OS.
+     */
+    public static final String PERMISSION_BIND =
+            "android.permission.BIND_JOB_SERVICE";
+
+    /**
+     * Identifier for a message that will result in a call to
+     * {@link #onStartJob(android.app.job.JobParameters)}.
+     */
+    private final int MSG_EXECUTE_JOB = 0;
+    /**
+     * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}.
+     */
+    private final int MSG_STOP_JOB = 1;
+    /**
+     * Message that the client has completed execution of this job.
+     */
+    private final int MSG_JOB_FINISHED = 2;
+
+    /** Lock object for {@link #mHandler}. */
+    private final Object mHandlerLock = new Object();
+
+    /**
+     * Handler we post jobs to. Responsible for calling into the client logic, and handling the
+     * callback to the system.
+     */
+    @GuardedBy("mHandlerLock")
+    JobHandler mHandler;
+
+    /** Binder for this service. */
+    IJobService mBinder = new IJobService.Stub() {
+        @Override
+        public void startJob(JobParameters jobParams) {
+            ensureHandler();
+            Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
+            m.sendToTarget();
+        }
+        @Override
+        public void stopJob(JobParameters jobParams) {
+            ensureHandler();
+            Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
+            m.sendToTarget();
+        }
+    };
+
+    /** @hide */
+    void ensureHandler() {
+        synchronized (mHandlerLock) {
+            if (mHandler == null) {
+                mHandler = new JobHandler(getMainLooper());
+            }
+        }
+    }
+
+    /**
+     * Runs on application's main thread - callbacks are meant to offboard work to some other
+     * (app-specified) mechanism.
+     * @hide
+     */
+    class JobHandler extends Handler {
+        JobHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final JobParameters params = (JobParameters) msg.obj;
+            switch (msg.what) {
+                case MSG_EXECUTE_JOB:
+                    try {
+                        boolean workOngoing = JobService.this.onStartJob(params);
+                        ackStartMessage(params, workOngoing);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Error while executing job: " + params.getJobId());
+                        throw new RuntimeException(e);
+                    }
+                    break;
+                case MSG_STOP_JOB:
+                    try {
+                        boolean ret = JobService.this.onStopJob(params);
+                        ackStopMessage(params, ret);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Application unable to handle onStopJob.", e);
+                        throw new RuntimeException(e);
+                    }
+                    break;
+                case MSG_JOB_FINISHED:
+                    final boolean needsReschedule = (msg.arg2 == 1);
+                    IJobCallback callback = params.getCallback();
+                    if (callback != null) {
+                        try {
+                            callback.jobFinished(params.getJobId(), needsReschedule);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error reporting job finish to system: binder has gone" +
+                                    "away.");
+                        }
+                    } else {
+                        Log.e(TAG, "finishJob() called for a nonexistent job id.");
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Unrecognised message received.");
+                    break;
+            }
+        }
+
+        private void ackStartMessage(JobParameters params, boolean workOngoing) {
+            final IJobCallback callback = params.getCallback();
+            final int jobId = params.getJobId();
+            if (callback != null) {
+                try {
+                     callback.acknowledgeStartMessage(jobId, workOngoing);
+                } catch(RemoteException e) {
+                    Log.e(TAG, "System unreachable for starting job.");
+                }
+            } else {
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Attempting to ack a job that has already been processed.");
+                }
+            }
+        }
+
+        private void ackStopMessage(JobParameters params, boolean reschedule) {
+            final IJobCallback callback = params.getCallback();
+            final int jobId = params.getJobId();
+            if (callback != null) {
+                try {
+                    callback.acknowledgeStopMessage(jobId, reschedule);
+                } catch(RemoteException e) {
+                    Log.e(TAG, "System unreachable for stopping job.");
+                }
+            } else {
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Attempting to ack a job that has already been processed.");
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public final IBinder onBind(Intent intent) {
+        return mBinder.asBinder();
+    }
+
+    /**
+     * Override this method with the callback logic for your job. Any such logic needs to be
+     * performed on a separate thread, as this function is executed on your application's main
+     * thread.
+     *
+     * @param params Parameters specifying info about this job, including the extras bundle you
+     *               optionally provided at job-creation time.
+     * @return True if your service needs to process the work (on a separate thread). False if
+     * there's no more work to be done for this job.
+     */
+    public abstract boolean onStartJob(JobParameters params);
+
+    /**
+     * This method is called if the system has determined that you must stop execution of your job
+     * even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}.
+     *
+     * <p>This will happen if the requirements specified at schedule time are no longer met. For
+     * example you may have requested WiFi with
+     * {@link android.app.job.JobInfo.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+     * job was executing the user toggled WiFi. Another example is if you had specified
+     * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+     * idle maintenance window. You are solely responsible for the behaviour of your application
+     * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
+     * immediate repercussion is that the system will cease holding a wakelock for you.</p>
+     *
+     * @param params Parameters specifying info about this job.
+     * @return True to indicate to the JobManager whether you'd like to reschedule this job based
+     * on the retry criteria provided at job creation-time. False to drop the job. Regardless of
+     * the value returned, your job must stop executing.
+     */
+    public abstract boolean onStopJob(JobParameters params);
+
+    /**
+     * Callback to inform the JobManager you've finished executing. This can be called from any
+     * thread, as it will ultimately be run on your application's main thread. When the system
+     * receives this message it will release the wakelock being held.
+     * <p>
+     *     You can specify post-execution behaviour to the scheduler here with
+     *     <code>needsReschedule </code>. This will apply a back-off timer to your job based on
+     *     the default, or what was set with
+     *     {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}. The original
+     *     requirements are always honoured even for a backed-off job. Note that a job running in
+     *     idle mode will not be backed-off. Instead what will happen is the job will be re-added
+     *     to the queue and re-executed within a future idle maintenance window.
+     * </p>
+     *
+     * @param params Parameters specifying system-provided info about this job, this was given to
+     *               your application in {@link #onStartJob(JobParameters)}.
+     * @param needsReschedule True if this job is complete, false if you want the JobManager to
+     *                        reschedule you.
+     */
+    public final void jobFinished(JobParameters params, boolean needsReschedule) {
+        ensureHandler();
+        Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
+        m.arg2 = needsReschedule ? 1 : 0;
+        m.sendToTarget();
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl
deleted file mode 100644
index 582dede..0000000
--- a/core/java/android/app/maintenance/IIdleCallback.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.maintenance;
-
-import android.app.maintenance.IIdleService;
-
-/**
- * The server side of the idle maintenance IPC protocols.  The app-side implementation
- * invokes on this interface to indicate completion of the (asynchronous) instructions
- * issued by the server.
- *
- * In all cases, the 'who' parameter is the caller's service binder, used to track
- * which idle service instance is reporting.
- *
- * {@hide}
- */
-interface IIdleCallback {
-    /**
-     * Acknowledge receipt and processing of the asynchronous "start idle work" incall.
-     * 'result' is true if the app wants some time to perform ongoing background
-     * idle-time work; or false if the app declares that it does not need any time
-     * for such work.
-     */
-    void acknowledgeStart(int token, boolean result);
-
-    /**
-     * Acknowledge receipt and processing of the asynchronous "stop idle work" incall.
-     */
-    void acknowledgeStop(int token);
-
-    /*
-     * Tell the idle service manager that we're done with our idle maintenance, so that
-     * it can go on to the next one and stop attributing wakelock time to us etc.
-     *
-     * @param opToken The identifier passed in the startIdleMaintenance() call that
-     *        indicated the beginning of this service's idle timeslice.
-     */
-    void idleFinished(int token);
-}
diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl
deleted file mode 100644
index 54abccd..0000000
--- a/core/java/android/app/maintenance/IIdleService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.maintenance;
-
-import android.app.maintenance.IIdleCallback;
-
-/**
- * Interface that the framework uses to communicate with application code
- * that implements an idle-time "maintenance" service.  End user code does
- * not implement this interface directly; instead, the app's idle service
- * implementation will extend android.app.maintenance.IdleService.
- * {@hide}
- */
-oneway interface IIdleService {
-    /**
-     * Begin your idle-time work.
-     */
-    void startIdleMaintenance(IIdleCallback callbackBinder, int token);
-    void stopIdleMaintenance(IIdleCallback callbackBinder, int token);
-}
diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java
deleted file mode 100644
index 2331b81..0000000
--- a/core/java/android/app/maintenance/IdleService.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.maintenance;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Slog;
-
-/**
- * Idle maintenance API.  Full docs TBW (to be written).
- */
-public abstract class IdleService extends Service {
-    private static final String TAG = "IdleService";
-
-    static final int MSG_START = 1;
-    static final int MSG_STOP = 2;
-    static final int MSG_FINISH = 3;
-
-    IdleHandler mHandler;
-    IIdleCallback mCallbackBinder;
-    int mToken;
-    final Object mHandlerLock = new Object();
-
-    void ensureHandler() {
-        synchronized (mHandlerLock) {
-            if (mHandler == null) {
-                mHandler = new IdleHandler(getMainLooper());
-            }
-        }
-    }
-
-    /**
-     * TBW: the idle service should supply an intent-filter handling this intent
-     * <p>
-     * <p class="note">The application must also protect the idle service with the
-     * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other
-     * applications cannot maliciously bind to it.  If an idle service's manifest
-     * declaration does not require that permission, it will never be invoked.
-     * </p>
-     */
-    @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE =
-            "android.service.idle.IdleService";
-
-    /**
-     * Idle services must be protected with this permission:
-     *
-     * <pre class="prettyprint">
-     *     <service android:name="MyIdleService"
-     *              android:permission="android.permission.BIND_IDLE_SERVICE" >
-     *         ...
-     *     </service>
-     * </pre>
-     *
-     * <p>If an idle service is declared in the manifest but not protected with this
-     * permission, that service will be ignored by the OS.
-     */
-    public static final String PERMISSION_BIND =
-            "android.permission.BIND_IDLE_SERVICE";
-
-    // Trampoline: the callbacks are always run on the main thread
-    IIdleService mBinder = new IIdleService.Stub() {
-        @Override
-        public void startIdleMaintenance(IIdleCallback callbackBinder, int token)
-                throws RemoteException {
-            ensureHandler();
-            Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder);
-            mHandler.sendMessage(msg);
-        }
-
-        @Override
-        public void stopIdleMaintenance(IIdleCallback callbackBinder, int token)
-                throws RemoteException {
-            ensureHandler();
-            Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder);
-            mHandler.sendMessage(msg);
-        }
-    };
-
-    /**
-     * Your application may begin doing "idle" maintenance work in the background.
-     * <p>
-     * Your application may continue to run in the background until it receives a call
-     * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work.  The
-     * OS will hold a wakelock on your application's behalf from the time this method is
-     * called until after the following call to {@link #onIdleStop()} returns.
-     * </p>
-     * <p>
-     * Returning {@code false} from this method indicates that you have no ongoing work
-     * to do at present.  The OS will respond by immediately calling {@link #onIdleStop()}
-     * and returning your application to its normal stopped state.  Returning {@code true}
-     * indicates that the application is indeed performing ongoing work, so the OS will
-     * let your application run in this state until it's no longer appropriate.
-     * </p>
-     * <p>
-     * You will always receive a matching call to {@link #onIdleStop()} even if your
-     * application returns {@code false} from this method.
-     *
-     * @return {@code true} to indicate that the application wishes to perform some ongoing
-     *     background work; {@code false} to indicate that it does not need to perform such
-     *     work at present.
-     */
-    public abstract boolean onIdleStart();
-
-    /**
-     * Your app's maintenance opportunity is over.  Once the application returns from
-     * this method, the wakelock held by the OS on its behalf will be released.
-     */
-    public abstract void onIdleStop();
-
-    /**
-     * Tell the OS that you have finished your idle work.  Calling this more than once,
-     * or calling it when you have not received an {@link #onIdleStart()} callback, is
-     * an error.
-     *
-     * <p>It is safe to call {@link #finishIdle()} from any thread.
-     */
-    public final void finishIdle() {
-        ensureHandler();
-        mHandler.sendEmptyMessage(MSG_FINISH);
-    }
-
-    class IdleHandler extends Handler {
-        IdleHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_START: {
-                    // Call the concrete onIdleStart(), reporting its return value back to
-                    // the OS.  If onIdleStart() throws, report it as a 'false' return but
-                    // rethrow the exception at the offending app.
-                    boolean result = false;
-                    IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
-                    mCallbackBinder = callbackBinder;
-                    final int token = mToken = msg.arg1;
-                    try {
-                        result = IdleService.this.onIdleStart();
-                    } catch (Exception e) {
-                        Log.e(TAG, "Unable to start idle workload", e);
-                        throw new RuntimeException(e);
-                    } finally {
-                        // don't bother if the service already called finishIdle()
-                        if (mCallbackBinder != null) {
-                            try {
-                                callbackBinder.acknowledgeStart(token, result);
-                            } catch (RemoteException re) {
-                                Log.e(TAG, "System unreachable to start idle workload");
-                            }
-                        }
-                    }
-                    break;
-                }
-
-                case MSG_STOP: {
-                    // Structured just like MSG_START for the stop-idle bookend call.
-                    IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
-                    final int token = msg.arg1;
-                    try {
-                        IdleService.this.onIdleStop();
-                    } catch (Exception e) {
-                        Log.e(TAG, "Unable to stop idle workload", e);
-                        throw new RuntimeException(e);
-                    } finally {
-                        if (mCallbackBinder != null) {
-                            try {
-                                callbackBinder.acknowledgeStop(token);
-                            } catch (RemoteException re) {
-                                Log.e(TAG, "System unreachable to stop idle workload");
-                            }
-                        }
-                    }
-                    break;
-                }
-
-                case MSG_FINISH: {
-                    if (mCallbackBinder != null) {
-                        try {
-                            mCallbackBinder.idleFinished(mToken);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "System unreachable to finish idling");
-                        } finally {
-                            mCallbackBinder = null;
-                        }
-                    } else {
-                        Log.e(TAG, "finishIdle() called but the idle service is not started");
-                    }
-                    break;
-                }
-
-                default: {
-                    Slog.w(TAG, "Unknown message " + msg.what);
-                }
-            }
-        }
-    }
-
-    /** @hide */
-    @Override
-    public final IBinder onBind(Intent intent) {
-        return mBinder.asBinder();
-    }
-
-}
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
deleted file mode 100644
index d8a32fd..0000000
--- a/core/java/android/app/task/ITaskCallback.aidl
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.task;
-
-import android.app.task.ITaskService;
-import android.app.task.TaskParams;
-
-/**
- * The server side of the TaskManager IPC protocols.  The app-side implementation
- * invokes on this interface to indicate completion of the (asynchronous) instructions
- * issued by the server.
- *
- * In all cases, the 'who' parameter is the caller's service binder, used to track
- * which Task Service instance is reporting.
- *
- * {@hide}
- */
-interface ITaskCallback {
-    /**
-     * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
-     *
-     * @param taskId Unique integer used to identify this task.
-     * @param ongoing True to indicate that the client is processing the task. False if the task is
-     * complete
-     */
-    void acknowledgeStartMessage(int taskId, boolean ongoing);
-    /**
-     * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
-     *
-     * @param taskId Unique integer used to identify this task.
-     * @param rescheulde Whether or not to reschedule this task.
-     */
-    void acknowledgeStopMessage(int taskId, boolean reschedule);
-    /*
-     * Tell the task manager that the client is done with its execution, so that it can go on to
-     * the next one and stop attributing wakelock time to us etc.
-     *
-     * @param taskId Unique integer used to identify this task.
-     * @param reschedule Whether or not to reschedule this task.
-     */
-    void taskFinished(int taskId, boolean reschedule);
-}
diff --git a/core/java/android/app/task/TaskManager.java b/core/java/android/app/task/TaskManager.java
deleted file mode 100644
index 00f57da..0000000
--- a/core/java/android/app/task/TaskManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.app.task;
-
-import java.util.List;
-
-import android.content.Context;
-
-/**
- * Class for scheduling various types of tasks with the scheduling framework on the device.
- *
- * <p>You do not
- * instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.TASK_SERVICE)}.
- */
-public abstract class TaskManager {
-    /*
-     * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
-     * if the run-time for your task is too short, or perhaps the system can't resolve the
-     * requisite {@link TaskService} in your package.
-     */
-    public static final int RESULT_FAILURE = 0;
-    /**
-     * Returned from {@link #schedule(Task)} if this application has made too many requests for
-     * work over too short a time.
-     */
-    // TODO: Determine if this is necessary.
-    public static final int RESULT_SUCCESS = 1;
-
-    /**
-     * @param task The task you wish scheduled. See
-     * {@link android.app.task.Task.Builder Task.Builder} for more detail on the sorts of tasks
-     * you can schedule.
-     * @return If >0, this int returns the taskId of the successfully scheduled task.
-     * Otherwise you have to compare the return value to the error codes defined in this class.
-     */
-    public abstract int schedule(Task task);
-
-    /**
-     * Cancel a task that is pending in the TaskManager.
-     * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
-     * {@link #getAllPendingTasks()}.
-     * @return
-     */
-    public abstract void cancel(int taskId);
-
-    /**
-     * Cancel all tasks that have been registered with the TaskManager by this package.
-     */
-    public abstract void cancelAll();
-
-    /**
-     * @return a list of all the tasks registered by this package that have not yet been executed.
-     */
-    public abstract List<Task> getAllPendingTasks();
-
-}
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
deleted file mode 100644
index f4908c6..0000000
--- a/core/java/android/app/task/TaskParams.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.app.task;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-
-/**
- * Contains the parameters used to configure/identify your task. You do not create this object
- * yourself, instead it is handed in to your application by the System.
- */
-public class TaskParams implements Parcelable {
-
-    private final int taskId;
-    private final PersistableBundle extras;
-    private final IBinder callback;
-
-    /** @hide */
-    public TaskParams(int taskId, PersistableBundle extras, IBinder callback) {
-        this.taskId = taskId;
-        this.extras = extras;
-        this.callback = callback;
-    }
-
-    /**
-     * @return The unique id of this task, specified at creation time.
-     */
-    public int getTaskId() {
-        return taskId;
-    }
-
-    /**
-     * @return The extras you passed in when constructing this task with
-     * {@link android.app.task.Task.Builder#setExtras(android.os.PersistableBundle)}. This will
-     * never be null. If you did not set any extras this will be an empty bundle.
-     */
-    public PersistableBundle getExtras() {
-        return extras;
-    }
-
-    /** @hide */
-    public ITaskCallback getCallback() {
-        return ITaskCallback.Stub.asInterface(callback);
-    }
-
-    private TaskParams(Parcel in) {
-        taskId = in.readInt();
-        extras = in.readPersistableBundle();
-        callback = in.readStrongBinder();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(taskId);
-        dest.writePersistableBundle(extras);
-        dest.writeStrongBinder(callback);
-    }
-
-    public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
-        @Override
-        public TaskParams createFromParcel(Parcel in) {
-            return new TaskParams(in);
-        }
-
-        @Override
-        public TaskParams[] newArray(int size) {
-            return new TaskParams[size];
-        }
-    };
-}
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
deleted file mode 100644
index 8ce4484..0000000
--- a/core/java/android/app/task/TaskService.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.app.task;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * <p>Entry point for the callback from the {@link android.app.task.TaskManager}.</p>
- * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
- * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
- * you will implement your task logic.</p>
- * <p>This service executes each incoming task on a {@link android.os.Handler} running on your
- * application's main thread. This means that you <b>must</b> offload your execution logic to
- * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
- * in blocking any future callbacks from the TaskManager - specifically
- * {@link #onStopTask(android.app.task.TaskParams)}, which is meant to inform you that the
- * scheduling requirements are no longer being met.</p>
- */
-public abstract class TaskService extends Service {
-    private static final String TAG = "TaskService";
-
-    /**
-     * Task services must be protected with this permission:
-     *
-     * <pre class="prettyprint">
-     *     <service android:name="MyTaskService"
-     *              android:permission="android.permission.BIND_TASK_SERVICE" >
-     *         ...
-     *     </service>
-     * </pre>
-     *
-     * <p>If a task service is declared in the manifest but not protected with this
-     * permission, that service will be ignored by the OS.
-     */
-    public static final String PERMISSION_BIND =
-            "android.permission.BIND_TASK_SERVICE";
-
-    /**
-     * Identifier for a message that will result in a call to
-     * {@link #onStartTask(android.app.task.TaskParams)}.
-     */
-    private final int MSG_EXECUTE_TASK = 0;
-    /**
-     * Message that will result in a call to {@link #onStopTask(android.app.task.TaskParams)}.
-     */
-    private final int MSG_STOP_TASK = 1;
-    /**
-     * Message that the client has completed execution of this task.
-     */
-    private final int MSG_TASK_FINISHED = 2;
-
-    /** Lock object for {@link #mHandler}. */
-    private final Object mHandlerLock = new Object();
-
-    /**
-     * Handler we post tasks to. Responsible for calling into the client logic, and handling the
-     * callback to the system.
-     */
-    @GuardedBy("mHandlerLock")
-    TaskHandler mHandler;
-
-    /** Binder for this service. */
-    ITaskService mBinder = new ITaskService.Stub() {
-        @Override
-        public void startTask(TaskParams taskParams) {
-            ensureHandler();
-            Message m = Message.obtain(mHandler, MSG_EXECUTE_TASK, taskParams);
-            m.sendToTarget();
-        }
-        @Override
-        public void stopTask(TaskParams taskParams) {
-            ensureHandler();
-            Message m = Message.obtain(mHandler, MSG_STOP_TASK, taskParams);
-            m.sendToTarget();
-        }
-    };
-
-    /** @hide */
-    void ensureHandler() {
-        synchronized (mHandlerLock) {
-            if (mHandler == null) {
-                mHandler = new TaskHandler(getMainLooper());
-            }
-        }
-    }
-
-    /**
-     * Runs on application's main thread - callbacks are meant to offboard work to some other
-     * (app-specified) mechanism.
-     * @hide
-     */
-    class TaskHandler extends Handler {
-        TaskHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final TaskParams params = (TaskParams) msg.obj;
-            switch (msg.what) {
-                case MSG_EXECUTE_TASK:
-                    try {
-                        boolean workOngoing = TaskService.this.onStartTask(params);
-                        ackStartMessage(params, workOngoing);
-                    } catch (Exception e) {
-                        Log.e(TAG, "Error while executing task: " + params.getTaskId());
-                        throw new RuntimeException(e);
-                    }
-                    break;
-                case MSG_STOP_TASK:
-                    try {
-                        boolean ret = TaskService.this.onStopTask(params);
-                        ackStopMessage(params, ret);
-                    } catch (Exception e) {
-                        Log.e(TAG, "Application unable to handle onStopTask.", e);
-                        throw new RuntimeException(e);
-                    }
-                    break;
-                case MSG_TASK_FINISHED:
-                    final boolean needsReschedule = (msg.arg2 == 1);
-                    ITaskCallback callback = params.getCallback();
-                    if (callback != null) {
-                        try {
-                            callback.taskFinished(params.getTaskId(), needsReschedule);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error reporting task finish to system: binder has gone" +
-                                    "away.");
-                        }
-                    } else {
-                        Log.e(TAG, "finishTask() called for a nonexistent task id.");
-                    }
-                    break;
-                default:
-                    Log.e(TAG, "Unrecognised message received.");
-                    break;
-            }
-        }
-
-        private void ackStartMessage(TaskParams params, boolean workOngoing) {
-            final ITaskCallback callback = params.getCallback();
-            final int taskId = params.getTaskId();
-            if (callback != null) {
-                try {
-                     callback.acknowledgeStartMessage(taskId, workOngoing);
-                } catch(RemoteException e) {
-                    Log.e(TAG, "System unreachable for starting task.");
-                }
-            } else {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Attempting to ack a task that has already been processed.");
-                }
-            }
-        }
-
-        private void ackStopMessage(TaskParams params, boolean reschedule) {
-            final ITaskCallback callback = params.getCallback();
-            final int taskId = params.getTaskId();
-            if (callback != null) {
-                try {
-                    callback.acknowledgeStopMessage(taskId, reschedule);
-                } catch(RemoteException e) {
-                    Log.e(TAG, "System unreachable for stopping task.");
-                }
-            } else {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Attempting to ack a task that has already been processed.");
-                }
-            }
-        }
-    }
-
-    /** @hide */
-    public final IBinder onBind(Intent intent) {
-        return mBinder.asBinder();
-    }
-
-    /**
-     * Override this method with the callback logic for your task. Any such logic needs to be
-     * performed on a separate thread, as this function is executed on your application's main
-     * thread.
-     *
-     * @param params Parameters specifying info about this task, including the extras bundle you
-     *               optionally provided at task-creation time.
-     * @return True if your service needs to process the work (on a separate thread). False if
-     * there's no more work to be done for this task.
-     */
-    public abstract boolean onStartTask(TaskParams params);
-
-    /**
-     * This method is called if the system has determined that you must stop execution of your task
-     * even before you've had a chance to call {@link #taskFinished(TaskParams, boolean)}.
-     *
-     * <p>This will happen if the requirements specified at schedule time are no longer met. For
-     * example you may have requested WiFi with
-     * {@link android.app.task.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
-     * task was executing the user toggled WiFi. Another example is if you had specified
-     * {@link android.app.task.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
-     * idle maintenance window. You are solely responsible for the behaviour of your application
-     * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
-     * immediate repercussion is that the system will cease holding a wakelock for you.</p>
-     *
-     * @param params Parameters specifying info about this task.
-     * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
-     * on the retry criteria provided at task creation-time. False to drop the task. Regardless of
-     * the value returned, your task must stop executing.
-     */
-    public abstract boolean onStopTask(TaskParams params);
-
-    /**
-     * Callback to inform the TaskManager you've finished executing. This can be called from any
-     * thread, as it will ultimately be run on your application's main thread. When the system
-     * receives this message it will release the wakelock being held.
-     * <p>
-     *     You can specify post-execution behaviour to the scheduler here with
-     *     <code>needsReschedule </code>. This will apply a back-off timer to your task based on
-     *     the default, or what was set with
-     *     {@link android.app.task.Task.Builder#setBackoffCriteria(long, int)}. The original
-     *     requirements are always honoured even for a backed-off task. Note that a task running in
-     *     idle mode will not be backed-off. Instead what will happen is the task will be re-added
-     *     to the queue and re-executed within a future idle maintenance window.
-     * </p>
-     *
-     * @param params Parameters specifying system-provided info about this task, this was given to
-     *               your application in {@link #onStartTask(TaskParams)}.
-     * @param needsReschedule True if this task is complete, false if you want the TaskManager to
-     *                        reschedule you.
-     */
-    public final void taskFinished(TaskParams params, boolean needsReschedule) {
-        ensureHandler();
-        Message m = Message.obtain(mHandler, MSG_TASK_FINISHED, params);
-        m.arg2 = needsReschedule ? 1 : 0;
-        m.sendToTarget();
-    }
-}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 7b709ac..5175490 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -90,6 +90,11 @@
     public static final String ACTION_PLAYING_STATE_CHANGED =
         "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
 
+    /** @hide */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
+
     /**
      * A2DP sink device is streaming music. This state can be one of
      * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
new file mode 100644
index 0000000..2e27345
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -0,0 +1,432 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth A2DP Sink
+ * profile.
+ *
+ *<p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothA2dpSink proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothA2dpSink implements BluetoothProfile {
+    private static final String TAG = "BluetoothA2dpSink";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    /**
+     * Intent used to broadcast the change in connection state of the A2DP Sink
+     * profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     */
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
+
+    /**
+     * Intent used to broadcast the change in the Playing state of the A2DP Sink
+     * profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+     * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     */
+    public static final String ACTION_PLAYING_STATE_CHANGED =
+        "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED";
+
+    /**
+     * A2DP sink device is streaming music. This state can be one of
+     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+     */
+    public static final int STATE_PLAYING   =  10;
+
+    /**
+     * A2DP sink device is NOT streaming music. This state can be one of
+     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+     */
+    public static final int STATE_NOT_PLAYING   =  11;
+
+    /**
+     * Intent used to broadcast the change in the Playing state of the A2DP Sink
+     * profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     */
+    public static final String ACTION_AUDIO_CONFIG_CHANGED =
+        "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED";
+
+    /**
+     * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent.
+     *
+     * This extra represents the current audio configuration of the A2DP source device.
+     * {@see BluetoothAudioConfig}
+     */
+    public static final String EXTRA_AUDIO_CONFIG
+            = "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
+
+    private Context mContext;
+    private ServiceListener mServiceListener;
+    private IBluetoothA2dpSink mService;
+    private BluetoothAdapter mAdapter;
+
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (VDBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (VDBG) Log.d(TAG,"Binding service...");
+                                    doBind();
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+    /**
+     * Create a BluetoothA2dp proxy object for interacting with the local
+     * Bluetooth A2DP service.
+     *
+     */
+    /*package*/ BluetoothA2dpSink(Context context, ServiceListener l) {
+        mContext = context;
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothA2dpSink.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+                android.os.Process.myUserHandle())) {
+            Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
+            return false;
+        }
+        return true;
+    }
+
+    /*package*/ void close() {
+        mServiceListener = null;
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
+    }
+
+    public void finalize() {
+        close();
+    }
+    /**
+     * Initiate connection to a profile of the remote bluetooth device.
+     *
+     * <p> Currently, the system supports only 1 connection to the
+     * A2DP profile. The API will automatically disconnect connected
+     * devices before connecting.
+     *
+     * <p> This API returns false in scenarios like the profile on the
+     * device is already connected or Bluetooth is not turned on.
+     * When this API returns true, it is guaranteed that
+     * connection state intent for the profile will be broadcasted with
+     * the state. Users can get the connection state of the profile
+     * from this intent.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     * permission.
+     *
+     * @param device Remote Bluetooth Device
+     * @return false on immediate error,
+     *               true otherwise
+     * @hide
+     */
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) log("connect(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.connect(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Initiate disconnection from a profile
+     *
+     * <p> This API will return false in scenarios like the profile on the
+     * Bluetooth device is not in connected state etc. When this API returns,
+     * true, it is guaranteed that the connection state change
+     * intent will be broadcasted with the state. Users can get the
+     * disconnection state of the profile from this intent.
+     *
+     * <p> If the disconnection is initiated by a remote device, the state
+     * will transition from {@link #STATE_CONNECTED} to
+     * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+     * host (local) device the state will transition from
+     * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+     * state {@link #STATE_DISCONNECTED}. The transition to
+     * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+     * two scenarios.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     * permission.
+     *
+     * @param device Remote Bluetooth Device
+     * @return false on immediate error,
+     *               true otherwise
+     * @hide
+     */
+    public boolean disconnect(BluetoothDevice device) {
+        if (DBG) log("disconnect(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.disconnect(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (VDBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (VDBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (VDBG) log("getState(" + device + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Get the current audio configuration for the A2DP source device,
+     * or null if the device has no audio configuration
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device Remote bluetooth device.
+     * @return audio configuration for the device, or null
+     *
+     * {@see BluetoothAudioConfig}
+     */
+          public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
+        if (VDBG) log("getAudioConfig(" + device + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.getAudioConfig(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return null;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return null;
+    }
+
+    /**
+     * Helper for converting a state to a string.
+     *
+     * For debug use only - strings are not internationalized.
+     * @hide
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+        case STATE_DISCONNECTED:
+            return "disconnected";
+        case STATE_CONNECTING:
+            return "connecting";
+        case STATE_CONNECTED:
+            return "connected";
+        case STATE_DISCONNECTING:
+            return "disconnecting";
+        case STATE_PLAYING:
+            return "playing";
+        case STATE_NOT_PLAYING:
+          return "not playing";
+        default:
+            return "<unknown state " + state + ">";
+        }
+    }
+
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) Log.d(TAG, "Proxy object connected");
+            mService = IBluetoothA2dpSink.Stub.asInterface(service);
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
+                        BluetoothA2dpSink.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) Log.d(TAG, "Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK);
+            }
+        }
+    };
+
+    private boolean isEnabled() {
+       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+       return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
+    }
+
+    private static void log(String msg) {
+      Log.d(TAG, msg);
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 42c2aeb..ba42f51b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -1390,6 +1390,12 @@
         } else if (profile == BluetoothProfile.A2DP) {
             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.A2DP_SINK) {
+            BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
+            return true;
+        } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
+            BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
+            return true;
         } else if (profile == BluetoothProfile.INPUT_DEVICE) {
             BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
             return true;
@@ -1402,6 +1408,9 @@
         } else if (profile == BluetoothProfile.MAP) {
             BluetoothMap map = new BluetoothMap(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
+            BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -1430,6 +1439,14 @@
                 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
                 a2dp.close();
                 break;
+            case BluetoothProfile.A2DP_SINK:
+                BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy;
+                a2dpSink.close();
+                break;
+            case BluetoothProfile.AVRCP_CONTROLLER:
+                BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy;
+                avrcp.close();
+                break;
             case BluetoothProfile.INPUT_DEVICE:
                 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
                 iDev.close();
@@ -1454,6 +1471,10 @@
                 BluetoothMap map = (BluetoothMap)proxy;
                 map.close();
                 break;
+            case BluetoothProfile.HEADSET_CLIENT:
+                BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
+                headsetClient.close();
+                break;
         }
     }
 
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/bluetooth/BluetoothAudioConfig.aidl
similarity index 82%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/bluetooth/BluetoothAudioConfig.aidl
index 1f25439..63be5cf 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/bluetooth/BluetoothAudioConfig.aidl
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2014 The Android Open Source Project
+/*
+ * 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.bluetooth;
 
-parcelable Task;
- 
\ No newline at end of file
+parcelable BluetoothAudioConfig;
diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.java b/core/java/android/bluetooth/BluetoothAudioConfig.java
new file mode 100644
index 0000000..03176b9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAudioConfig.java
@@ -0,0 +1,111 @@
+/*
+ * 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 android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the audio configuration for a Bluetooth A2DP source device.
+ *
+ * {@see BluetoothA2dpSink}
+ *
+ * {@hide}
+ */
+public final class BluetoothAudioConfig implements Parcelable {
+
+    private final int mSampleRate;
+    private final int mChannelConfig;
+    private final int mAudioFormat;
+
+    public BluetoothAudioConfig(int sampleRate, int channelConfig, int audioFormat) {
+        mSampleRate = sampleRate;
+        mChannelConfig = channelConfig;
+        mAudioFormat = audioFormat;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BluetoothAudioConfig) {
+            BluetoothAudioConfig bac = (BluetoothAudioConfig)o;
+            return (bac.mSampleRate == mSampleRate &&
+                    bac.mChannelConfig == mChannelConfig &&
+                    bac.mAudioFormat == mAudioFormat);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mSampleRate | (mChannelConfig << 24) | (mAudioFormat << 28);
+    }
+
+    @Override
+    public String toString() {
+        return "{mSampleRate:" + mSampleRate + ",mChannelConfig:" + mChannelConfig
+                + ",mAudioFormat:" + mAudioFormat + "}";
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<BluetoothAudioConfig> CREATOR =
+            new Parcelable.Creator<BluetoothAudioConfig>() {
+        public BluetoothAudioConfig createFromParcel(Parcel in) {
+            int sampleRate = in.readInt();
+            int channelConfig = in.readInt();
+            int audioFormat = in.readInt();
+            return new BluetoothAudioConfig(sampleRate, channelConfig, audioFormat);
+        }
+        public BluetoothAudioConfig[] newArray(int size) {
+            return new BluetoothAudioConfig[size];
+        }
+    };
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSampleRate);
+        out.writeInt(mChannelConfig);
+        out.writeInt(mAudioFormat);
+    }
+
+    /**
+     * Returns the sample rate in samples per second
+     * @return sample rate
+     */
+    public int getSampleRate() {
+        return mSampleRate;
+    }
+
+    /**
+     * Returns the channel configuration (either {@link android.media.AudioFormat#CHANNEL_IN_MONO}
+     * or {@link android.media.AudioFormat#CHANNEL_IN_STEREO})
+     * @return channel configuration
+     */
+    public int getChannelConfig() {
+        return mChannelConfig;
+    }
+
+    /**
+     * Returns the channel audio format (either {@link android.media.AudioFormat#ENCODING_PCM_16BIT}
+     * or {@link android.media.AudioFormat#ENCODING_PCM_8BIT}
+     * @return audio format
+     */
+    public int getAudioFormat() {
+        return mAudioFormat;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothAvrcp.java b/core/java/android/bluetooth/BluetoothAvrcp.java
new file mode 100644
index 0000000..44fe1b7
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcp.java
@@ -0,0 +1,93 @@
+/*
+ * 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.bluetooth;
+
+/**
+ * This class contains constants for Bluetooth AVRCP profile.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcp {
+
+    /*
+     * State flags for Passthrough commands
+    */
+    public static final int PASSTHROUGH_STATE_PRESS    = 0;
+    public static final int PASSTHROUGH_STATE_RELEASE  = 1;
+
+    /*
+     * Operation IDs for Passthrough commands
+    */
+    public static final int PASSTHROUGH_ID_SELECT      = 0x00;    /* select */
+    public static final int PASSTHROUGH_ID_UP          = 0x01;    /* up */
+    public static final int PASSTHROUGH_ID_DOWN        = 0x02;    /* down */
+    public static final int PASSTHROUGH_ID_LEFT        = 0x03;    /* left */
+    public static final int PASSTHROUGH_ID_RIGHT       = 0x04;    /* right */
+    public static final int PASSTHROUGH_ID_RIGHT_UP    = 0x05;    /* right-up */
+    public static final int PASSTHROUGH_ID_RIGHT_DOWN  = 0x06;    /* right-down */
+    public static final int PASSTHROUGH_ID_LEFT_UP     = 0x07;    /* left-up */
+    public static final int PASSTHROUGH_ID_LEFT_DOWN   = 0x08;    /* left-down */
+    public static final int PASSTHROUGH_ID_ROOT_MENU   = 0x09;    /* root menu */
+    public static final int PASSTHROUGH_ID_SETUP_MENU  = 0x0A;    /* setup menu */
+    public static final int PASSTHROUGH_ID_CONT_MENU   = 0x0B;    /* contents menu */
+    public static final int PASSTHROUGH_ID_FAV_MENU    = 0x0C;    /* favorite menu */
+    public static final int PASSTHROUGH_ID_EXIT        = 0x0D;    /* exit */
+    public static final int PASSTHROUGH_ID_0           = 0x20;    /* 0 */
+    public static final int PASSTHROUGH_ID_1           = 0x21;    /* 1 */
+    public static final int PASSTHROUGH_ID_2           = 0x22;    /* 2 */
+    public static final int PASSTHROUGH_ID_3           = 0x23;    /* 3 */
+    public static final int PASSTHROUGH_ID_4           = 0x24;    /* 4 */
+    public static final int PASSTHROUGH_ID_5           = 0x25;    /* 5 */
+    public static final int PASSTHROUGH_ID_6           = 0x26;    /* 6 */
+    public static final int PASSTHROUGH_ID_7           = 0x27;    /* 7 */
+    public static final int PASSTHROUGH_ID_8           = 0x28;    /* 8 */
+    public static final int PASSTHROUGH_ID_9           = 0x29;    /* 9 */
+    public static final int PASSTHROUGH_ID_DOT         = 0x2A;    /* dot */
+    public static final int PASSTHROUGH_ID_ENTER       = 0x2B;    /* enter */
+    public static final int PASSTHROUGH_ID_CLEAR       = 0x2C;    /* clear */
+    public static final int PASSTHROUGH_ID_CHAN_UP     = 0x30;    /* channel up */
+    public static final int PASSTHROUGH_ID_CHAN_DOWN   = 0x31;    /* channel down */
+    public static final int PASSTHROUGH_ID_PREV_CHAN   = 0x32;    /* previous channel */
+    public static final int PASSTHROUGH_ID_SOUND_SEL   = 0x33;    /* sound select */
+    public static final int PASSTHROUGH_ID_INPUT_SEL   = 0x34;    /* input select */
+    public static final int PASSTHROUGH_ID_DISP_INFO   = 0x35;    /* display information */
+    public static final int PASSTHROUGH_ID_HELP        = 0x36;    /* help */
+    public static final int PASSTHROUGH_ID_PAGE_UP     = 0x37;    /* page up */
+    public static final int PASSTHROUGH_ID_PAGE_DOWN   = 0x38;    /* page down */
+    public static final int PASSTHROUGH_ID_POWER       = 0x40;    /* power */
+    public static final int PASSTHROUGH_ID_VOL_UP      = 0x41;    /* volume up */
+    public static final int PASSTHROUGH_ID_VOL_DOWN    = 0x42;    /* volume down */
+    public static final int PASSTHROUGH_ID_MUTE        = 0x43;    /* mute */
+    public static final int PASSTHROUGH_ID_PLAY        = 0x44;    /* play */
+    public static final int PASSTHROUGH_ID_STOP        = 0x45;    /* stop */
+    public static final int PASSTHROUGH_ID_PAUSE       = 0x46;    /* pause */
+    public static final int PASSTHROUGH_ID_RECORD      = 0x47;    /* record */
+    public static final int PASSTHROUGH_ID_REWIND      = 0x48;    /* rewind */
+    public static final int PASSTHROUGH_ID_FAST_FOR    = 0x49;    /* fast forward */
+    public static final int PASSTHROUGH_ID_EJECT       = 0x4A;    /* eject */
+    public static final int PASSTHROUGH_ID_FORWARD     = 0x4B;    /* forward */
+    public static final int PASSTHROUGH_ID_BACKWARD    = 0x4C;    /* backward */
+    public static final int PASSTHROUGH_ID_ANGLE       = 0x50;    /* angle */
+    public static final int PASSTHROUGH_ID_SUBPICT     = 0x51;    /* subpicture */
+    public static final int PASSTHROUGH_ID_F1          = 0x71;    /* F1 */
+    public static final int PASSTHROUGH_ID_F2          = 0x72;    /* F2 */
+    public static final int PASSTHROUGH_ID_F3          = 0x73;    /* F3 */
+    public static final int PASSTHROUGH_ID_F4          = 0x74;    /* F4 */
+    public static final int PASSTHROUGH_ID_F5          = 0x75;    /* F5 */
+    public static final int PASSTHROUGH_ID_VENDOR      = 0x7E;    /* vendor unique */
+    public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80;
+}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
new file mode 100644
index 0000000..b53a8fc
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -0,0 +1,260 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth AVRCP Controller
+ * profile.
+ *
+ *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothAvrcpController proxy object.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcpController implements BluetoothProfile {
+    private static final String TAG = "BluetoothAvrcpController";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    /**
+     * Intent used to broadcast the change in connection state of the AVRCP Controller
+     * profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     */
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
+
+    private Context mContext;
+    private ServiceListener mServiceListener;
+    private IBluetoothAvrcpController mService;
+    private BluetoothAdapter mAdapter;
+
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (VDBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (VDBG) Log.d(TAG,"Binding service...");
+                                    doBind();
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
+    /**
+     * Create a BluetoothAvrcpController proxy object for interacting with the local
+     * Bluetooth AVRCP service.
+     *
+     */
+    /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) {
+        mContext = context;
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothAvrcpController.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+                android.os.Process.myUserHandle())) {
+            Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
+            return false;
+        }
+        return true;
+    }
+
+    /*package*/ void close() {
+        mServiceListener = null;
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
+    }
+
+    public void finalize() {
+        close();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (VDBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (VDBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (VDBG) log("getState(" + device + ")");
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
+        if (DBG) Log.d(TAG, "sendPassThroughCmd");
+        if (mService != null && isEnabled()) {
+            try {
+                mService.sendPassThroughCmd(device, keyCode, keyState);
+                return;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
+                return;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+    }
+
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) Log.d(TAG, "Proxy object connected");
+            mService = IBluetoothAvrcpController.Stub.asInterface(service);
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
+                        BluetoothAvrcpController.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) Log.d(TAG, "Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER);
+            }
+        }
+    };
+
+    private boolean isEnabled() {
+       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+       return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
+    }
+
+    private static void log(String msg) {
+      Log.d(TAG, msg);
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
new file mode 100644
index 0000000..ff4ebee
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -0,0 +1,1167 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Public API to control Hands Free Profile (HFP role only).
+ * <p>
+ * This class defines methods that shall be used by application to manage profile
+ * connection, calls states and calls actions.
+ * <p>
+ *
+ * @hide
+ * */
+public final class BluetoothHeadsetClient implements BluetoothProfile {
+    private static final String TAG = "BluetoothHeadsetClient";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    /**
+     * Intent sent whenever connection to remote changes.
+     *
+     * <p>It includes two extras:
+     * <code>BluetoothProfile.EXTRA_PREVIOUS_STATE</code>
+     * and <code>BluetoothProfile.EXTRA_STATE</code>, which
+     * are mandatory.
+     * <p>There are also non mandatory feature extras:
+     * {@link #EXTRA_AG_FEATURE_3WAY_CALLING},
+     * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION},
+     * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT},
+     * {@link #EXTRA_AG_FEATURE_REJECT_CALL},
+     * {@link #EXTRA_AG_FEATURE_ECC},
+     * {@link #EXTRA_AG_FEATURE_RESPONSE_AND_HOLD},
+     * {@link #EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL},
+     * {@link #EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL},
+     * {@link #EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT},
+     * {@link #EXTRA_AG_FEATURE_MERGE},
+     * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH},
+     * sent as boolean values only when <code>EXTRA_STATE</code>
+     * is set to <code>STATE_CONNECTED</code>.</p>
+     *
+     * <p>Note that features supported by AG are being sent as
+     * booleans with value <code>true</code>,
+     * and not supported ones are <strong>not</strong> being sent at all.</p>
+     */
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED";
+
+    /**
+     * Intent sent whenever audio state changes.
+     *
+     * <p>It includes two mandatory extras:
+     * {@link BluetoothProfile.EXTRA_STATE},
+     * {@link BluetoothProfile.EXTRA_PREVIOUS_STATE},
+     * with possible values:
+     * {@link #STATE_AUDIO_CONNECTING},
+     * {@link #STATE_AUDIO_CONNECTED},
+     * {@link #STATE_AUDIO_DISCONNECTED}</p>
+     * <p>When <code>EXTRA_STATE</code> is set
+     * to </code>STATE_AUDIO_CONNECTED</code>,
+     * it also includes {@link #EXTRA_AUDIO_WBS}
+     * indicating wide band speech support.</p>
+     */
+    public static final String ACTION_AUDIO_STATE_CHANGED =
+        "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
+
+    /**
+     * Intent sending updates of the Audio Gateway state.
+     * Each extra is being sent only when value it
+     * represents has been changed recently on AG.
+     * <p>It can contain one or more of the following extras:
+     * {@link #EXTRA_NETWORK_STATUS},
+     * {@link #EXTRA_NETWORK_SIGNAL_STRENGTH},
+     * {@link #EXTRA_NETWORK_ROAMING},
+     * {@link #EXTRA_BATTERY_LEVEL},
+     * {@link #EXTRA_OPERATOR_NAME},
+     * {@link #EXTRA_VOICE_RECOGNITION},
+     * {@link #EXTRA_IN_BAND_RING}</p>
+     */
+    public static final String ACTION_AG_EVENT =
+            "android.bluetooth.headsetclient.profile.action.AG_EVENT";
+
+    /**
+     * Intent sent whenever state of a call changes.
+     *
+     * <p>It includes:
+     * {@link #EXTRA_CALL},
+     * with value of {@link BluetoothHeadsetClientCall} instance,
+     * representing actual call state.</p>
+     */
+    public static final String ACTION_CALL_CHANGED =
+            "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";
+
+    /**
+     * Intent that notifies about the result of the last issued action.
+     * Please note that not every action results in explicit action result code being sent.
+     * Instead other notifications about new Audio Gateway state might be sent,
+     * like <code>ACTION_AG_EVENT</code> with <code>EXTRA_VOICE_RECOGNITION</code> value
+     * when for example user started voice recognition from HF unit.
+     */
+    public static final String ACTION_RESULT =
+            "android.bluetooth.headsetclient.profile.action.RESULT";
+
+    /**
+     * Intent that notifies about the number attached to the last voice tag
+     * recorded on AG.
+     *
+     * <p>It contains:
+     * {@link #EXTRA_NUMBER},
+     * with a <code>String</code> value representing phone number.</p>
+     */
+    public static final String ACTION_LAST_VTAG =
+            "android.bluetooth.headsetclient.profile.action.LAST_VTAG";
+
+    public static final int STATE_AUDIO_DISCONNECTED = 0;
+    public static final int STATE_AUDIO_CONNECTING = 1;
+    public static final int STATE_AUDIO_CONNECTED = 2;
+
+    /**
+     * Extra with information if connected audio is WBS.
+     * <p>Possible values: <code>true</code>,
+     *                     <code>false</code>.</p>
+     */
+    public static final String EXTRA_AUDIO_WBS =
+            "android.bluetooth.headsetclient.extra.AUDIO_WBS";
+
+    /**
+     * Extra for AG_EVENT indicates network status.
+     * <p>Value: 0 - network unavailable,
+     *           1 - network available </p>
+     */
+    public static final String EXTRA_NETWORK_STATUS =
+            "android.bluetooth.headsetclient.extra.NETWORK_STATUS";
+    /**
+     * Extra for AG_EVENT intent indicates network signal strength.
+     * <p>Value: <code>Integer</code> representing signal strength.</p>
+     */
+    public static final String EXTRA_NETWORK_SIGNAL_STRENGTH =
+            "android.bluetooth.headsetclient.extra.NETWORK_SIGNAL_STRENGTH";
+    /**
+     * Extra for AG_EVENT intent indicates roaming state.
+     * <p>Value: 0 - no roaming
+     *           1 - active roaming</p>
+     */
+    public static final String EXTRA_NETWORK_ROAMING =
+            "android.bluetooth.headsetclient.extra.NETWORK_ROAMING";
+    /**
+     * Extra for AG_EVENT intent indicates the battery level.
+     * <p>Value: <code>Integer</code> representing signal strength.</p>
+     */
+    public static final String EXTRA_BATTERY_LEVEL =
+            "android.bluetooth.headsetclient.extra.BATTERY_LEVEL";
+    /**
+     * Extra for AG_EVENT intent indicates operator name.
+     * <p>Value: <code>String</code> representing operator name.</p>
+     */
+    public static final String EXTRA_OPERATOR_NAME =
+            "android.bluetooth.headsetclient.extra.OPERATOR_NAME";
+    /**
+     * Extra for AG_EVENT intent indicates voice recognition state.
+     * <p>Value:
+     *          0 - voice recognition stopped,
+     *          1 - voice recognition started.</p>
+     */
+    public static final String EXTRA_VOICE_RECOGNITION =
+            "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION";
+    /**
+     * Extra for AG_EVENT intent indicates in band ring state.
+     * <p>Value:
+     *          0 - in band ring tone not supported, or
+     *          1 - in band ring tone supported.</p>
+     */
+    public static final String EXTRA_IN_BAND_RING =
+            "android.bluetooth.headsetclient.extra.IN_BAND_RING";
+
+    /**
+     * Extra for AG_EVENT intent indicates subscriber info.
+     * <p>Value: <code>String</code> containing subscriber information.</p>
+     */
+    public static final String EXTRA_SUBSCRIBER_INFO =
+            "android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO";
+
+    /**
+     *  Extra for AG_CALL_CHANGED intent indicates the
+     *  {@link BluetoothHeadsetClientCall} object that has changed.
+     */
+    public static final String EXTRA_CALL =
+            "android.bluetooth.headsetclient.extra.CALL";
+
+    /**
+     * Extra for ACTION_LAST_VTAG intent.
+     * <p>Value: <code>String</code> representing phone number
+     * corresponding to last voice tag recorded on AG</p>
+     */
+    public static final String EXTRA_NUMBER =
+            "android.bluetooth.headsetclient.extra.NUMBER";
+
+    /**
+     * Extra for ACTION_RESULT intent that shows the result code of
+     * last issued action.
+     * <p>Possible results:
+     * {@link #ACTION_RESULT_OK},
+     * {@link #ACTION_RESULT_ERROR},
+     * {@link #ACTION_RESULT_ERROR_NO_CARRIER},
+     * {@link #ACTION_RESULT_ERROR_BUSY},
+     * {@link #ACTION_RESULT_ERROR_NO_ANSWER},
+     * {@link #ACTION_RESULT_ERROR_DELAYED},
+     * {@link #ACTION_RESULT_ERROR_BLACKLISTED},
+     * {@link #ACTION_RESULT_ERROR_CME}</p>
+     */
+    public static final String EXTRA_RESULT_CODE =
+            "android.bluetooth.headsetclient.extra.RESULT_CODE";
+
+    /**
+     * Extra for ACTION_RESULT intent that shows the extended result code of
+     * last issued action.
+     * <p>Value: <code>Integer</code> - error code.</p>
+     */
+    public static final String EXTRA_CME_CODE =
+            "android.bluetooth.headsetclient.extra.CME_CODE";
+
+    /* Extras for AG_FEATURES, extras type is boolean */
+    // TODO verify if all of those are actually useful
+    /**
+     * AG feature: three way calling.
+     */
+    public final static String EXTRA_AG_FEATURE_3WAY_CALLING =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_3WAY_CALLING";
+    /**
+     * AG feature: voice recognition.
+     */
+    public final static String EXTRA_AG_FEATURE_VOICE_RECOGNITION =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_VOICE_RECOGNITION";
+    /**
+     * AG feature: fetching phone number for voice tagging procedure.
+     */
+    public final static String EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT";
+    /**
+     * AG feature: ability to reject incoming call.
+     */
+    public final static String EXTRA_AG_FEATURE_REJECT_CALL =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_REJECT_CALL";
+    /**
+     * AG feature: enhanced call handling (terminate specific call, private consultation).
+     */
+    public final static String EXTRA_AG_FEATURE_ECC =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ECC";
+    /**
+     * AG feature: response and hold.
+     */
+    public final static String EXTRA_AG_FEATURE_RESPONSE_AND_HOLD =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RESPONSE_AND_HOLD";
+    /**
+     * AG call handling feature: accept held or waiting call in three way calling scenarios.
+     */
+    public final static String EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL";
+    /**
+     * AG call handling feature: release held or waiting call in three way calling scenarios.
+     */
+    public final static String EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL";
+    /**
+     * AG call handling feature: release active call and accept held or waiting call in three way
+     * calling scenarios.
+     */
+    public final static String EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT";
+    /**
+     * AG call handling feature: merge two calls, held and active - multi party conference mode.
+     */
+    public final static String EXTRA_AG_FEATURE_MERGE =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE";
+    /**
+     * AG call handling feature: merge calls and disconnect from multi party
+     * conversation leaving peers connected to each other.
+     * Note that this feature needs to be supported by mobile network operator
+     * as it requires connection and billing transfer.
+     */
+    public final static String EXTRA_AG_FEATURE_MERGE_AND_DETACH =
+            "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE_AND_DETACH";
+
+    /* Action result codes */
+    public final static int ACTION_RESULT_OK = 0;
+    public final static int ACTION_RESULT_ERROR = 1;
+    public final static int ACTION_RESULT_ERROR_NO_CARRIER = 2;
+    public final static int ACTION_RESULT_ERROR_BUSY = 3;
+    public final static int ACTION_RESULT_ERROR_NO_ANSWER = 4;
+    public final static int ACTION_RESULT_ERROR_DELAYED = 5;
+    public final static int ACTION_RESULT_ERROR_BLACKLISTED = 6;
+    public final static int ACTION_RESULT_ERROR_CME = 7;
+
+    /* Detailed CME error codes */
+    public final static int CME_PHONE_FAILURE                           = 0;
+    public final static int CME_NO_CONNECTION_TO_PHONE                  = 1;
+    public final static int CME_OPERATION_NOT_ALLOWED                   = 3;
+    public final static int CME_OPERATION_NOT_SUPPORTED                 = 4;
+    public final static int CME_PHSIM_PIN_REQUIRED                      = 5;
+    public final static int CME_PHFSIM_PIN_REQUIRED                     = 6;
+    public final static int CME_PHFSIM_PUK_REQUIRED                     = 7;
+    public final static int CME_SIM_NOT_INSERTED                        = 10;
+    public final static int CME_SIM_PIN_REQUIRED                        = 11;
+    public final static int CME_SIM_PUK_REQUIRED                        = 12;
+    public final static int CME_SIM_FAILURE                             = 13;
+    public final static int CME_SIM_BUSY                                = 14;
+    public final static int CME_SIM_WRONG                               = 15;
+    public final static int CME_INCORRECT_PASSWORD                      = 16;
+    public final static int CME_SIM_PIN2_REQUIRED                       = 17;
+    public final static int CME_SIM_PUK2_REQUIRED                       = 18;
+    public final static int CME_MEMORY_FULL                             = 20;
+    public final static int CME_INVALID_INDEX                           = 21;
+    public final static int CME_NOT_FOUND                               = 22;
+    public final static int CME_MEMORY_FAILURE                          = 23;
+    public final static int CME_TEXT_STRING_TOO_LONG                    = 24;
+    public final static int CME_INVALID_CHARACTER_IN_TEXT_STRING        = 25;
+    public final static int CME_DIAL_STRING_TOO_LONG                    = 26;
+    public final static int CME_INVALID_CHARACTER_IN_DIAL_STRING        = 27;
+    public final static int CME_NO_NETWORK_SERVICE                      = 30;
+    public final static int CME_NETWORK_TIMEOUT                         = 31;
+    public final static int CME_EMERGENCY_SERVICE_ONLY                  = 32;
+    public final static int CME_NO_SIMULTANOUS_VOIP_CS_CALLS            = 33;
+    public final static int CME_NOT_SUPPORTED_FOR_VOIP                  = 34;
+    public final static int CME_SIP_RESPONSE_CODE                       = 35;
+    public final static int CME_NETWORK_PERSONALIZATION_PIN_REQUIRED    = 40;
+    public final static int CME_NETWORK_PERSONALIZATION_PUK_REQUIRED    = 41;
+    public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED   = 42;
+    public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED   = 43;
+    public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED = 44;
+    public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED = 45;
+    public final static int CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED  = 46;
+    public final static int CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED  = 47;
+    public final static int CME_HIDDEN_KEY_REQUIRED                     = 48;
+    public final static int CME_EAP_NOT_SUPPORTED                       = 49;
+    public final static int CME_INCORRECT_PARAMETERS                    = 50;
+
+    /* Action policy for other calls when accepting call */
+    public static final int CALL_ACCEPT_NONE = 0;
+    public static final int CALL_ACCEPT_HOLD = 1;
+    public static final int CALL_ACCEPT_TERMINATE = 2;
+
+    private Context mContext;
+    private ServiceListener mServiceListener;
+    private IBluetoothHeadsetClient mService;
+    private BluetoothAdapter mAdapter;
+
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                @Override
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (VDBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (VDBG) Log.d(TAG,"Binding service...");
+                                    Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
+                                    doBind();
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
+    /**
+     * Create a BluetoothHeadsetClient proxy object.
+     */
+    /*package*/ BluetoothHeadsetClient(Context context, ServiceListener l) {
+        mContext = context;
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+                 android.os.Process.myUserHandle())) {
+            Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Close the connection to the backing service.
+     * Other public functions of BluetoothHeadsetClient will return default error
+     * results once close() has been called. Multiple invocations of close()
+     * are ok.
+     */
+    /*package*/ void close() {
+        if (VDBG) log("close()");
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
+        mServiceListener = null;
+    }
+
+    /**
+     * Connects to remote device.
+     *
+     * Currently, the system supports only 1 connection. So, in case of the
+     * second connection, this implementation will disconnect already connected
+     * device automatically and will process the new one.
+     *
+     * @param device    a remote device we want connect to
+     * @return <code>true</code> if command has been issued successfully;
+     *          <code>false</code> otherwise;
+     *          upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}
+     *          intent.
+     */
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) log("connect(" + device + ")");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.connect(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Disconnects remote device
+     *
+     * @param device    a remote device we want disconnect
+     * @return          <code>true</code> if command has been issued successfully;
+     *                  <code>false</code> otherwise;
+     *                  upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}
+     *                  intent.
+     */
+    public boolean disconnect(BluetoothDevice device) {
+        if (DBG) log("disconnect(" + device + ")");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.disconnect(device);
+            } catch (RemoteException e) {
+              Log.e(TAG, Log.getStackTraceString(new Throwable()));
+              return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Return the list of connected remote devices
+     *
+     * @return list of connected devices; empty list if nothing is connected.
+     */
+    @Override
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (VDBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Returns list of remote devices in a particular state
+     *
+     * @param states    collection of states
+     * @return          list of devices that state matches the states listed in
+     *                  <code>states</code>; empty list if nothing matches the
+     *                  <code>states</code>
+     */
+    @Override
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (VDBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Returns state of the <code>device</code>
+     *
+     * @param device    a remote device
+     * @return          the state of connection of the device
+     */
+    @Override
+    public int getConnectionState(BluetoothDevice device) {
+        if (VDBG) log("getConnectionState(" + device + ")");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Set priority of the profile
+     *
+     * The device should already be paired.
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            if (priority != BluetoothProfile.PRIORITY_OFF &&
+                    priority != BluetoothProfile.PRIORITY_ON) {
+              return false;
+            }
+            try {
+                return mService.setPriority(device, priority);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Get the priority of the profile.
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (VDBG) log("getPriority(" + device + ")");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.getPriority(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return PRIORITY_OFF;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return PRIORITY_OFF;
+    }
+
+    /**
+     * Starts voice recognition.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_AG_EVENT}
+     *                   intent.
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean startVoiceRecognition(BluetoothDevice device) {
+        if (DBG) log("startVoiceRecognition()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.startVoiceRecognition(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Stops voice recognition.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_AG_EVENT}
+     *                   intent.
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean stopVoiceRecognition(BluetoothDevice device) {
+        if (DBG) log("stopVoiceRecognition()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.stopVoiceRecognition(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Returns list of all calls in any state.
+     *
+     * @param device    remote device
+     * @return          list of calls; empty list if none call exists
+     */
+    public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
+        if (DBG) log("getCurrentCalls()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.getCurrentCalls(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return null;
+    }
+
+    /**
+     * Returns list of current values of AG indicators.
+     *
+     * @param device    remote device
+     * @return          bundle of AG  indicators; null if device is not in
+     *                  CONNECTED state
+     */
+    public Bundle getCurrentAgEvents(BluetoothDevice device) {
+        if (DBG) log("getCurrentCalls()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.getCurrentAgEvents(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return null;
+    }
+
+    /**
+     * Accepts a call
+     *
+     * @param device    remote device
+     * @param flag      action policy while accepting a call. Possible values
+     *                   {@link #CALL_ACCEPT_NONE}, {@link #CALL_ACCEPT_HOLD},
+     *                   {@link #CALL_ACCEPT_TERMINATE}
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent.
+     */
+    public boolean acceptCall(BluetoothDevice device, int flag) {
+        if (DBG) log("acceptCall()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.acceptCall(device, flag);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Holds a call.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent.
+     */
+    public boolean holdCall(BluetoothDevice device) {
+        if (DBG) log("holdCall()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.holdCall(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Rejects a call.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent.
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_REJECT_CALL}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean rejectCall(BluetoothDevice device) {
+        if (DBG) log("rejectCall()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.rejectCall(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Terminates a specified call.
+     *
+     * Works only when Extended Call Control is supported by Audio Gateway.
+     *
+     * @param device    remote device
+     * @param index     index of the call to be terminated
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent.
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_ECC}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean terminateCall(BluetoothDevice device, int index) {
+        if (DBG) log("terminateCall()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.terminateCall(device, index);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Enters private mode with a specified call.
+     *
+     * Works only when Extended Call Control is supported by Audio Gateway.
+     *
+     * @param device    remote device
+     * @param index     index of the call to connect in private mode
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent.
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_ECC}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean enterPrivateMode(BluetoothDevice device, int index) {
+        if (DBG) log("enterPrivateMode()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.enterPrivateMode(device, index);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Performs explicit call transfer.
+     *
+     * That means connect other calls and disconnect.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent.
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean explicitCallTransfer(BluetoothDevice device) {
+        if (DBG) log("explicitCallTransfer()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.explicitCallTransfer(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Redials last number from Audio Gateway.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent in case of success; {@link #ACTION_RESULT} is sent
+     *                   otherwise;
+     */
+    public boolean redial(BluetoothDevice device) {
+        if (DBG) log("redial()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.redial(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Places a call with specified number.
+     *
+     * @param device    remote device
+     * @param number    valid phone number
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent in case of success; {@link #ACTION_RESULT} is sent
+     *                   otherwise;
+     */
+    public boolean dial(BluetoothDevice device, String number) {
+        if (DBG) log("dial()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.dial(device, number);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Places a call to the number under specified memory location.
+     *
+     * @param device    remote device
+     * @param location  valid memory location
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+     *                   intent in case of success; {@link #ACTION_RESULT} is sent
+     *                   otherwise;
+     */
+    public boolean dialMemory(BluetoothDevice device, int location) {
+        if (DBG) log("dialMemory()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.dialMemory(device, location);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Sends DTMF code.
+     *
+     * Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,#
+     *
+     * @param device    remote device
+     * @param code  ASCII code
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_RESULT} intent;
+     */
+    public boolean sendDTMF(BluetoothDevice device, byte code) {
+        if (DBG) log("sendDTMF()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.sendDTMF(device, code);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Get a number corresponding to last voice tag recorded on AG.
+     *
+     * @param device    remote device
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_LAST_VTAG}
+     *                   or {@link #ACTION_RESULT} intent;
+     *
+     * <p>Feature required for successful execution is being reported by:
+     * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}.
+     * This method invocation will fail silently when feature is not supported.</p>
+     */
+    public boolean getLastVoiceTagNumber(BluetoothDevice device) {
+        if (DBG) log("getLastVoiceTagNumber()");
+        if (mService != null && isEnabled() &&
+                isValidDevice(device)) {
+            try {
+                return mService.getLastVoiceTagNumber(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,  Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Accept the incoming connection.
+     */
+    public boolean acceptIncomingConnect(BluetoothDevice device) {
+        if (DBG) log("acceptIncomingConnect");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.acceptIncomingConnect(device);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Reject the incoming connection.
+     */
+    public boolean rejectIncomingConnect(BluetoothDevice device) {
+        if (DBG) log("rejectIncomingConnect");
+        if (mService != null) {
+            try {
+                return mService.rejectIncomingConnect(device);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Returns current audio state of Audio Gateway.
+     *
+     * Note: This is an internal function and shouldn't be exposed
+     */
+    public int getAudioState(BluetoothDevice device) {
+        if (VDBG) log("getAudioState");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getAudioState(device);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
+    }
+
+    /**
+     * Initiates a connection of audio channel.
+     *
+     * It setup SCO channel with remote connected Handsfree AG device.
+     *
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
+     *                   intent;
+     */
+    public boolean connectAudio() {
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.connectAudio();
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Disconnects audio channel.
+     *
+     * It tears down the SCO channel from remote AG device.
+     *
+     * @return          <code>true</code> if command has been issued successfully;
+     *                   <code>false</code> otherwise;
+     *                   upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
+     *                   intent;
+     */
+    public boolean disconnectAudio() {
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.disconnectAudio();
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Get Audio Gateway features
+     *
+     * @param device    remote device
+     * @return          bundle of AG features; null if no service or
+     *                  AG not connected
+     */
+    public Bundle getCurrentAgFeatures(BluetoothDevice device) {
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getCurrentAgFeatures(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+        return null;
+    }
+
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) Log.d(TAG, "Proxy object connected");
+            mService = IBluetoothHeadsetClient.Stub.asInterface(service);
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
+                        BluetoothHeadsetClient.this);
+            }
+        }
+        @Override
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) Log.d(TAG, "Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);
+            }
+        }
+    };
+
+    private boolean isEnabled() {
+       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+       return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null) return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+       return false;
+    }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
similarity index 89%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
index 1f25439..35f7923 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.bluetooth;
 
-package android.app.task;
-
-parcelable Task;
- 
\ No newline at end of file
+parcelable BluetoothHeadsetClientCall;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
new file mode 100644
index 0000000..a15bd97
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -0,0 +1,218 @@
+/*
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class represents a single call, its state and properties.
+ * It implements {@link Parcelable} for inter-process message passing.
+ * @hide
+ */
+public final class BluetoothHeadsetClientCall implements Parcelable {
+
+    /* Call state */
+    /**
+     * Call is active.
+     */
+    public static final int CALL_STATE_ACTIVE = 0;
+    /**
+     * Call is in held state.
+     */
+    public static final int CALL_STATE_HELD = 1;
+    /**
+     * Outgoing call that is being dialed right now.
+     */
+    public static final int CALL_STATE_DIALING = 2;
+    /**
+     * Outgoing call that remote party has already been alerted about.
+     */
+    public static final int CALL_STATE_ALERTING = 3;
+    /**
+     * Incoming call that can be accepted or rejected.
+     */
+    public static final int CALL_STATE_INCOMING = 4;
+    /**
+     * Waiting call state when there is already an active call.
+     */
+    public static final int CALL_STATE_WAITING = 5;
+    /**
+     * Call that has been held by response and hold
+     * (see Bluetooth specification for further references).
+     */
+    public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6;
+    /**
+     * Call that has been already terminated and should not be referenced as a valid call.
+     */
+    public static final int CALL_STATE_TERMINATED = 7;
+
+    private final int mId;
+    private int mState;
+    private String mNumber;
+    private boolean mMultiParty;
+    private final boolean mOutgoing;
+
+    /**
+     * Creates BluetoothHeadsetClientCall instance.
+     */
+    public BluetoothHeadsetClientCall(int id, int state, String number, boolean multiParty,
+            boolean outgoing) {
+        mId = id;
+        mState = state;
+        mNumber = number != null ? number : "";
+        mMultiParty = multiParty;
+        mOutgoing = outgoing;
+    }
+
+    /**
+     * Sets call's state.
+     *
+     * <p>Note: This is an internal function and shouldn't be exposed</p>
+     *
+     * @param  state    new call state.
+     */
+    public void setState(int state) {
+        mState = state;
+    }
+
+    /**
+     * Sets call's number.
+     *
+     * <p>Note: This is an internal function and shouldn't be exposed</p>
+     *
+     * @param number    String representing phone number.
+     */
+    public void setNumber(String number) {
+        mNumber = number;
+    }
+
+    /**
+     * Sets this call as multi party call.
+     *
+     * <p>Note: This is an internal function and shouldn't be exposed</p>
+     *
+     * @param multiParty    if <code>true</code> sets this call as a part
+     *                      of multi party conference.
+     */
+    public void setMultiParty(boolean multiParty) {
+        mMultiParty = multiParty;
+    }
+
+    /**
+     * Gets call's Id.
+     *
+     * @return call id.
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Gets call's current state.
+     *
+     * @return state of this particular phone call.
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Gets call's number.
+     *
+     * @return string representing phone number.
+     */
+    public String getNumber() {
+        return mNumber;
+    }
+
+    /**
+     * Checks if call is an active call in a conference mode (aka multi party).
+     *
+     * @return <code>true</code> if call is a multi party call,
+     *         <code>false</code> otherwise.
+     */
+    public boolean isMultiParty() {
+        return mMultiParty;
+    }
+
+    /**
+     * Checks if this call is an outgoing call.
+     *
+     * @return <code>true</code> if its outgoing call,
+     *         <code>false</code> otherwise.
+     */
+    public boolean isOutgoing() {
+        return mOutgoing;
+    }
+
+    public String toString() {
+        StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mId: ");
+        builder.append(mId);
+        builder.append(", mState: ");
+        switch (mState) {
+            case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
+            case CALL_STATE_HELD: builder.append("HELD"); break;
+            case CALL_STATE_DIALING: builder.append("DIALING"); break;
+            case CALL_STATE_ALERTING: builder.append("ALERTING"); break;
+            case CALL_STATE_INCOMING: builder.append("INCOMING"); break;
+            case CALL_STATE_WAITING: builder.append("WAITING"); break;
+            case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: builder.append("HELD_BY_RESPONSE_AND_HOLD"); break;
+            case CALL_STATE_TERMINATED: builder.append("TERMINATED"); break;
+            default: builder.append(mState); break;
+        }
+        builder.append(", mNumber: ");
+        builder.append(mNumber);
+        builder.append(", mMultiParty: ");
+        builder.append(mMultiParty);
+        builder.append(", mOutgoing: ");
+        builder.append(mOutgoing);
+        builder.append("}");
+        return builder.toString();
+    }
+
+    /**
+     * {@link Parcelable.Creator} interface implementation.
+     */
+    public static final Parcelable.Creator<BluetoothHeadsetClientCall> CREATOR =
+            new Parcelable.Creator<BluetoothHeadsetClientCall>() {
+                @Override
+                public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
+                    return new BluetoothHeadsetClientCall(in.readInt(), in.readInt(),
+                            in.readString(), in.readInt() == 1, in.readInt() == 1);
+                }
+
+                @Override
+                public BluetoothHeadsetClientCall[] newArray(int size) {
+                    return new BluetoothHeadsetClientCall[size];
+                }
+            };
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mId);
+        out.writeInt(mState);
+        out.writeString(mNumber);
+        out.writeInt(mMultiParty ? 1 : 0);
+        out.writeInt(mOutgoing ? 1 : 0);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index d898060..1367405 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2010-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.
@@ -110,6 +110,18 @@
     public static final int A2DP_SINK = 10;
 
     /**
+     * AVRCP Controller Profile
+     * @hide
+     */
+    public static final int AVRCP_CONTROLLER = 11;
+
+    /**
+     * Headset Client - HFP HF Role
+     * @hide
+     */
+    public static final int HEADSET_CLIENT = 16;
+
+    /**
      * Default priority for devices that we try to auto-connect to and
      * and allow incoming connections for the profile
      * @hide
diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
new file mode 100644
index 0000000..b7c6476
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothAudioConfig;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth A2DP sink service
+ *
+ * @hide
+ */
+interface IBluetoothA2dpSink {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
+}
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
new file mode 100644
index 0000000..f917a50
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth AVRCP controller service
+ *
+ * @hide
+ */
+interface IBluetoothAvrcpController {
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
+}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 00a0750..273d76d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,8 +35,6 @@
 
     void startScan(in int appIf, in boolean isServer);
     void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
-    void startScanWithUuidsScanParam(in int appIf, in boolean isServer,
-                    in ParcelUuid[] ids, int scanWindow, int scanInterval);
     void startScanWithFilters(in int appIf, in boolean isServer,
                               in ScanSettings settings, in List<ScanFilter> filters);
     void stopScan(in int appIf, in boolean isServer);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index bf9e0a7..2d8eed4 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -22,7 +22,7 @@
  * Callback definitions for interacting with BLE / GATT
  * @hide
  */
-interface IBluetoothGattCallback {
+oneway interface IBluetoothGattCallback {
     void onClientRegistered(in int status, in int clientIf);
     void onClientConnectionState(in int status, in int clientIf,
                                  in boolean connected, in String address);
@@ -63,7 +63,7 @@
                              in int charInstId, in ParcelUuid charUuid,
                              in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
-    oneway void onAdvertiseStateChange(in int advertiseState, in int status);
-    oneway void onMultiAdvertiseCallback(in int status);
+    void onAdvertiseStateChange(in int advertiseState, in int status);
+    void onMultiAdvertiseCallback(in int status);
     void onConfigureMTU(in String address, in int mtu, in int status);
 }
diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
new file mode 100644
index 0000000..e518b7d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -0,0 +1,67 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClientCall;
+import android.os.Bundle;
+
+/**
+ * API for Bluetooth Headset Client service (HFP HF Role)
+ *
+ * {@hide}
+ */
+interface IBluetoothHeadsetClient {
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+
+    boolean acceptIncomingConnect(in BluetoothDevice device);
+    boolean rejectIncomingConnect(in BluetoothDevice device);
+
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+
+    boolean startVoiceRecognition(in BluetoothDevice device);
+    boolean stopVoiceRecognition(in BluetoothDevice device);
+
+    List<BluetoothHeadsetClientCall> getCurrentCalls(in BluetoothDevice device);
+    Bundle getCurrentAgEvents(in BluetoothDevice device);
+
+    boolean acceptCall(in BluetoothDevice device, int flag);
+    boolean holdCall(in BluetoothDevice device);
+    boolean rejectCall(in BluetoothDevice device);
+    boolean terminateCall(in BluetoothDevice device, int index);
+
+    boolean enterPrivateMode(in BluetoothDevice device, int index);
+    boolean explicitCallTransfer(in BluetoothDevice device);
+
+    boolean redial(in BluetoothDevice device);
+    boolean dial(in BluetoothDevice device, String number);
+    boolean dialMemory(in BluetoothDevice device, int location);
+
+    boolean sendDTMF(in BluetoothDevice device, byte code);
+    boolean getLastVoiceTagNumber(in BluetoothDevice device);
+
+    int getAudioState(in BluetoothDevice device);
+    boolean connectAudio();
+    boolean disconnectAudio();
+
+    Bundle getCurrentAgFeatures(in BluetoothDevice device);
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2897887..fd19b40 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2035,6 +2035,7 @@
             AUDIO_SERVICE,
             MEDIA_ROUTER_SERVICE,
             TELEPHONY_SERVICE,
+            TELECOMM_SERVICE,
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
             TEXT_SERVICES_MANAGER_SERVICE,
@@ -2059,7 +2060,7 @@
             PRINT_SERVICE,
             MEDIA_SESSION_SERVICE,
             BATTERY_SERVICE,
-            TASK_SERVICE,
+            JOB_SCHEDULER_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2116,8 +2117,8 @@
      * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
      * <dt> {@link #BATTERY_SERVICE} ("batterymanager")
      * <dd> A {@link android.os.BatteryManager} for managing battery state
-     * <dt> {@link #TASK_SERVICE} ("taskmanager")
-     * <dd>  A {@link android.app.task.TaskManager} for managing scheduled tasks
+     * <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
+     * <dd>  A {@link android.app.job.JobScheduler} for managing scheduled tasks
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -2163,6 +2164,8 @@
      * @see android.media.MediaRouter
      * @see #TELEPHONY_SERVICE
      * @see android.telephony.TelephonyManager
+     * @see #TELECOMM_SERVICE
+     * @see android.telecomm.TelecommManager
      * @see #INPUT_METHOD_SERVICE
      * @see android.view.inputmethod.InputMethodManager
      * @see #UI_MODE_SERVICE
@@ -2171,8 +2174,8 @@
      * @see android.app.DownloadManager
      * @see #BATTERY_SERVICE
      * @see android.os.BatteryManager
-     * @see #TASK_SERVICE
-     * @see android.app.task.TaskManager
+     * @see #JOB_SCHEDULER_SERVICE
+     * @see android.app.job.JobScheduler
      */
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
@@ -2494,6 +2497,16 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.telecomm.TelecommManager} to manage telecomm-related features
+     * of the device.
+     *
+     * @see #getSystemService
+     * @see android.telecomm.TelecommManager
+     */
+    public static final String TELECOMM_SERVICE = "telecomm";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.text.ClipboardManager} for accessing and modifying
      * the contents of the global clipboard.
      *
@@ -2769,12 +2782,12 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.app.task.TaskManager} instance for managing occasional
+     * android.app.job.JobScheduler} instance for managing occasional
      * background tasks.
      * @see #getSystemService
-     * @see android.app.task.TaskManager
+     * @see android.app.job.JobScheduler
      */
-    public static final String TASK_SERVICE = "task";
+    public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
 
     /**
      * Determine whether the given permission is allowed for a particular
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 04c0b9f..69fa408 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -67,7 +67,6 @@
          *
          * @param user The UserHandle of the profile that generated the change.
          * @param packageName The name of the package that was removed.
-         * @hide remove before ship
          */
         void onPackageRemoved(UserHandle user, String packageName);
 
@@ -76,7 +75,6 @@
          *
          * @param user The UserHandle of the profile that generated the change.
          * @param packageName The name of the package that was added.
-         * @hide remove before ship
          */
         void onPackageAdded(UserHandle user, String packageName);
 
@@ -85,7 +83,6 @@
          *
          * @param user The UserHandle of the profile that generated the change.
          * @param packageName The name of the package that has changed.
-         * @hide remove before ship
          */
         void onPackageChanged(UserHandle user, String packageName);
 
@@ -99,7 +96,6 @@
          *            available.
          * @param replacing Indicates whether these packages are replacing
          *            existing ones.
-         * @hide remove before ship
          */
         void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing);
 
@@ -113,59 +109,9 @@
          *            unavailable.
          * @param replacing Indicates whether the packages are about to be
          *            replaced with new versions.
-         * @hide remove before ship
          */
         void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing);
 
-        /**
-         * Indicates that a package was removed from the specified profile.
-         *
-         * @param packageName The name of the package that was removed.
-         * @param user The UserHandle of the profile that generated the change.
-         */
-        void onPackageRemoved(String packageName, UserHandle user);
-
-        /**
-         * Indicates that a package was added to the specified profile.
-         *
-         * @param packageName The name of the package that was added.
-         * @param user The UserHandle of the profile that generated the change.
-         */
-        void onPackageAdded(String packageName, UserHandle user);
-
-        /**
-         * Indicates that a package was modified in the specified profile.
-         *
-         * @param packageName The name of the package that has changed.
-         * @param user The UserHandle of the profile that generated the change.
-         */
-        void onPackageChanged(String packageName, UserHandle user);
-
-        /**
-         * Indicates that one or more packages have become available. For
-         * example, this can happen when a removable storage card has
-         * reappeared.
-         *
-         * @param packageNames The names of the packages that have become
-         *            available.
-         * @param user The UserHandle of the profile that generated the change.
-         * @param replacing Indicates whether these packages are replacing
-         *            existing ones.
-         */
-        void onPackagesAvailable(String [] packageNames, UserHandle user, boolean replacing);
-
-        /**
-         * Indicates that one or more packages have become unavailable. For
-         * example, this can happen when a removable storage card has been
-         * removed.
-         *
-         * @param packageNames The names of the packages that have become
-         *            unavailable.
-         * @param user The UserHandle of the profile that generated the change.
-         * @param replacing Indicates whether the packages are about to be
-         *            replaced with new versions.
-         */
-        void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
     }
 
     /** @hide */
@@ -361,8 +307,7 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackageRemoved(user, packageName); // TODO: Remove before ship
-                    listener.onPackageRemoved(packageName, user);
+                    listener.onPackageRemoved(user, packageName);
                 }
             }
         }
@@ -374,8 +319,7 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackageChanged(user, packageName); // TODO: Remove before ship
-                    listener.onPackageChanged(packageName, user);
+                    listener.onPackageChanged(user, packageName);
                 }
             }
         }
@@ -387,8 +331,7 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackageAdded(user, packageName); // TODO: Remove before ship
-                    listener.onPackageAdded(packageName, user);
+                    listener.onPackageAdded(user, packageName);
                 }
             }
         }
@@ -401,8 +344,7 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackagesAvailable(user, packageNames, replacing); // TODO: Remove
-                    listener.onPackagesAvailable(packageNames, user, replacing);
+                    listener.onPackagesAvailable(user, packageNames, replacing);
                 }
             }
         }
@@ -415,8 +357,7 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackagesUnavailable(user, packageNames, replacing); // TODO: Remove
-                    listener.onPackagesUnavailable(packageNames, user, replacing);
+                    listener.onPackagesUnavailable(user, packageNames, replacing);
                 }
             }
         }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 550c1f1..8d9b8d9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.PackageParser.PackageParserException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -2873,16 +2874,17 @@
         DisplayMetrics metrics = new DisplayMetrics();
         metrics.setToDefaults();
         final File sourceFile = new File(archiveFilePath);
-        PackageParser.Package pkg = packageParser.parsePackage(
-                sourceFile, archiveFilePath, metrics, 0);
-        if (pkg == null) {
+        try {
+            PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics,
+                    0);
+            if ((flags & GET_SIGNATURES) != 0) {
+                packageParser.collectCertificates(pkg, 0);
+            }
+            PackageUserState state = new PackageUserState();
+            return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
+        } catch (PackageParserException e) {
             return null;
         }
-        if ((flags & GET_SIGNATURES) != 0) {
-            packageParser.collectCertificates(pkg, 0);
-        }
-        PackageUserState state = new PackageUserState();
-        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4cac7fd..91895ff 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 
 import android.content.ComponentName;
 import android.content.Intent;
@@ -31,6 +32,7 @@
 import android.os.Bundle;
 import android.os.PatternMatcher;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Base64;
 import android.util.DisplayMetrics;
@@ -81,6 +83,8 @@
     private static final boolean DEBUG_PARSER = false;
     private static final boolean DEBUG_BACKUP = false;
 
+    // TODO: switch outError users to PackageParserException
+
     /** File name in an APK for the Android manifest. */
     private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
 
@@ -207,10 +211,10 @@
         }
     }
 
-    /* Light weight package info.
-     * @hide
+    /**
+     * Lightweight parsed details about a single APK file.
      */
-    public static class PackageLite {
+    public static class ApkLite {
         public final String packageName;
         public final String splitName;
         public final int versionCode;
@@ -218,7 +222,7 @@
         public final VerifierInfo[] verifiers;
         public final Signature[] signatures;
 
-        public PackageLite(String packageName, String splitName, int versionCode,
+        public ApkLite(String packageName, String splitName, int versionCode,
                 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
             this.packageName = packageName;
             this.splitName = splitName;
@@ -247,6 +251,10 @@
         mArchiveSourcePath = archiveSourcePath;
     }
 
+    public PackageParser(File archiveSource) {
+        this(archiveSource.getAbsolutePath());
+    }
+
     public void setSeparateProcesses(String[] procs) {
         mSeparateProcesses = procs;
     }
@@ -255,6 +263,10 @@
         mOnlyCoreApps = onlyCoreApps;
     }
 
+    private static final boolean isPackageFilename(File file) {
+        return isPackageFilename(file.getName());
+    }
+
     private static final boolean isPackageFilename(String name) {
         return name.endsWith(".apk");
     }
@@ -497,26 +509,84 @@
     public final static int PARSE_IS_PRIVILEGED = 1<<7;
     public final static int PARSE_GET_SIGNATURES = 1<<8;
 
-    public int getParseError() {
-        return mParseError;
+    /**
+     * Parse all APK files under the given directory as a single package.
+     */
+    public Package parseSplitPackage(File apkDir, DisplayMetrics metrics, int flags,
+            boolean trustedOverlay) throws PackageParserException {
+        final File[] files = apkDir.listFiles();
+        if (ArrayUtils.isEmpty(files)) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "No packages found in split");
+        }
+
+        File baseFile = null;
+        for (File file : files) {
+            if (file.isFile() && isPackageFilename(file)) {
+                ApkLite lite = parseApkLite(file.getAbsolutePath(), 0);
+                if (lite == null) {
+                    throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                            "Invalid package file: " + file);
+                }
+
+                if (TextUtils.isEmpty(lite.splitName)) {
+                    baseFile = file;
+                    break;
+                }
+            }
+        }
+
+        if (baseFile == null) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Missing base APK in " + apkDir);
+        }
+
+        final Package pkg = parseBaseApk(baseFile, metrics, flags, trustedOverlay);
+        if (pkg == null) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Failed to parse base APK: " + baseFile);
+        }
+
+        for (File file : files) {
+            if (file.isFile() && isPackageFilename(file) && !file.equals(baseFile)) {
+                parseSplitApk(pkg, file, metrics, flags, trustedOverlay);
+            }
+        }
+
+        // Always use a well-defined sort order
+        if (pkg.splitCodePaths != null) {
+            Arrays.sort(pkg.splitCodePaths);
+        }
+
+        return pkg;
     }
 
-    public Package parsePackage(File sourceFile, String destCodePath,
-            DisplayMetrics metrics, int flags) {
-        return parsePackage(sourceFile, destCodePath, metrics, flags, false);
+    public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags)
+            throws PackageParserException {
+        return parseMonolithicPackage(apkFile, metrics, flags, false);
     }
 
-    public Package parsePackage(File sourceFile, String destCodePath,
-            DisplayMetrics metrics, int flags, boolean trustedOverlay) {
+    public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags,
+            boolean trustedOverlay) throws PackageParserException {
+        final Package pkg = parseBaseApk(apkFile, metrics, flags, trustedOverlay);
+        if (pkg != null) {
+            return pkg;
+        } else {
+            throw new PackageParserException(mParseError, "Failed to parse " + apkFile);
+        }
+    }
+
+    private Package parseBaseApk(File apkFile, DisplayMetrics metrics, int flags,
+            boolean trustedOverlay) {
         mParseError = PackageManager.INSTALL_SUCCEEDED;
 
-        mArchiveSourcePath = sourceFile.getPath();
-        if (!sourceFile.isFile()) {
+        mArchiveSourcePath = apkFile.getAbsolutePath();
+        if (!apkFile.isFile()) {
             Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath);
             mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
             return null;
         }
-        if (!isPackageFilename(sourceFile.getName())
+        if (!isPackageFilename(apkFile.getName())
                 && (flags&PARSE_MUST_BE_APK) != 0) {
             if ((flags&PARSE_IS_SYSTEM) == 0) {
                 // We expect to have non-.apk files in the system dir,
@@ -560,13 +630,12 @@
         Exception errorException = null;
         try {
             // XXXX todo: need to figure out correct configuration.
-            pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
+            pkg = parseBaseApk(res, parser, flags, trustedOverlay, errorText);
         } catch (Exception e) {
             errorException = e;
             mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
         }
 
-
         if (pkg == null) {
             // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
             // just means to skip this app so don't make a fuss about it.
@@ -590,22 +659,25 @@
         parser.close();
         assmgr.close();
 
-        // Set code and resource paths
-        pkg.mPath = destCodePath;
-        pkg.mScanPath = mArchiveSourcePath;
-        //pkg.applicationInfo.sourceDir = destCodePath;
-        //pkg.applicationInfo.publicSourceDir = destRes;
+        pkg.codePath = mArchiveSourcePath;
         pkg.mSignatures = null;
 
         return pkg;
     }
 
+    private void parseSplitApk(Package pkg, File apkFile, DisplayMetrics metrics, int flags,
+            boolean trustedOverlay) throws PackageParserException {
+        // TODO: expand split APK parsing
+        pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths,
+                apkFile.getAbsolutePath());
+    }
+
     /**
      * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
      * APK. If it successfully scanned the package and found the
      * {@code AndroidManifest.xml}, {@code true} is returned.
      */
-    public boolean collectManifestDigest(Package pkg) {
+    public void collectManifestDigest(Package pkg) throws PackageParserException {
         try {
             final StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath);
             try {
@@ -616,13 +688,19 @@
             } finally {
                 jarFile.close();
             }
-            return true;
         } catch (IOException e) {
-            return false;
+            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Failed to collect manifest digest");
         }
     }
 
-    public boolean collectCertificates(Package pkg, int flags) {
+    public void collectCertificates(Package pkg, int flags) throws PackageParserException {
+        if (!collectCertificatesInternal(pkg, flags)) {
+            throw new PackageParserException(mParseError, "Failed to collect certificates");
+        }
+    }
+
+    private boolean collectCertificatesInternal(Package pkg, int flags) {
         pkg.mSignatures = null;
 
         WeakReference<byte[]> readBufferRef;
@@ -808,7 +886,7 @@
      * @param flags Special parse flags
      * @return PackageLite object with package information or null on failure.
      */
-    public static PackageLite parsePackageLite(String packageFilePath, int flags) {
+    public static ApkLite parseApkLite(String packageFilePath, int flags) {
         AssetManager assmgr = null;
         final XmlResourceParser parser;
         final Resources res;
@@ -844,9 +922,9 @@
 
         final AttributeSet attrs = parser;
         final String errors[] = new String[1];
-        PackageLite packageLite = null;
+        ApkLite packageLite = null;
         try {
-            packageLite = parsePackageLite(res, parser, attrs, flags, signatures, errors);
+            packageLite = parseApkLite(res, parser, attrs, flags, signatures, errors);
         } catch (PackageParserException e) {
             Slog.w(TAG, packageFilePath, e);
         } catch (IOException e) {
@@ -930,7 +1008,7 @@
                 (splitName != null) ? splitName.intern() : splitName);
     }
 
-    private static PackageLite parsePackageLite(Resources res, XmlPullParser parser,
+    private static ApkLite parseApkLite(Resources res, XmlPullParser parser,
             AttributeSet attrs, int flags, Signature[] signatures, String[] outError)
             throws IOException, XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
@@ -972,7 +1050,7 @@
             }
         }
 
-        return new PackageLite(packageSplit.first, packageSplit.second, versionCode,
+        return new ApkLite(packageSplit.first, packageSplit.second, versionCode,
                 installLocation, verifiers, signatures);
     }
 
@@ -988,9 +1066,8 @@
         return new Signature(sig);
     }
 
-    private Package parsePackage(
-        Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
-        String[] outError) throws XmlPullParserException, IOException {
+    private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+            boolean trustedOverlay, String[] outError) throws XmlPullParserException, IOException {
         AttributeSet attrs = parser;
 
         mParseInstrumentationArgs = null;
@@ -1019,7 +1096,13 @@
             }
         }
 
-        final Package pkg = new Package(pkgName, splitName);
+        if (!TextUtils.isEmpty(splitName)) {
+            outError[0] = "Expected base APK, but found split " + splitName;
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+            return null;
+        }
+
+        final Package pkg = new Package(pkgName);
         boolean foundApp = false;
 
         TypedArray sa = res.obtainAttributes(attrs,
@@ -3580,10 +3663,17 @@
         return true;
     }
 
+    /**
+     * Representation of a full package parsed from APK files on disk. A package
+     * consists of a single base APK, and zero or more split APKs.
+     */
     public final static class Package {
 
         public String packageName;
-        public String splitName;
+
+        // TODO: work towards making these paths invariant
+        public String codePath;
+        public String[] splitCodePaths;
 
         // For now we only support one application per package.
         public final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -3615,9 +3705,6 @@
         // We store the application meta-data independently to avoid multiple unwanted references
         public Bundle mAppMetaData = null;
 
-        // If this is a 3rd party app, this is the path of the zip file.
-        public String mPath;
-
         // The version code declared for this package.
         public int mVersionCode;
         
@@ -3637,10 +3724,6 @@
         // preferred up order.
         public int mPreferredOrder = 0;
 
-        // 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 needs to do dexopt.
         public boolean mDexOptNeeded = true;
 
@@ -3700,9 +3783,8 @@
         public Set<PublicKey> mSigningKeys;
         public Map<String, Set<PublicKey>> mKeySetMapping;
 
-        public Package(String packageName, String splitName) {
+        public Package(String packageName) {
             this.packageName = packageName;
-            this.splitName = splitName;
             applicationInfo.packageName = packageName;
             applicationInfo.uid = -1;
         }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index a07fc97..a83bd4a 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -17,11 +17,14 @@
 package android.content.res;
 
 import android.content.pm.ActivityInfo;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.view.View;
 
+import java.text.Format;
+import java.util.ArrayList;
 import java.util.Locale;
 
 /**
@@ -1306,4 +1309,240 @@
     private static int getScreenLayoutNoDirection(int screenLayout) {
         return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
     }
+
+    /**
+     *
+     * @hide
+     */
+    public static String localeToResourceQualifier(Locale locale) {
+        StringBuilder sb = new StringBuilder();
+        boolean l = (locale.getLanguage().length() != 0);
+        boolean c = (locale.getCountry().length() != 0);
+        boolean s = (locale.getScript().length() != 0);
+        boolean v = (locale.getVariant().length() != 0);
+
+        if (l) {
+            sb.append(locale.getLanguage());
+            if (c) {
+                sb.append("-r").append(locale.getCountry());
+                if (s) {
+                    sb.append("-s").append(locale.getScript());
+                    if (v) {
+                        sb.append("-v").append(locale.getVariant());
+                    }
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns a string representation of the configuration that can be parsed
+     * by build tools (like AAPT).
+     *
+     *
+     *
+     * @hide
+     */
+    public static String resourceQualifierString(Configuration config) {
+        ArrayList<String> parts = new ArrayList<String>();
+
+        if (config.mcc != 0) {
+            parts.add(config.mcc + "mcc");
+            if (config.mnc != 0) {
+                parts.add(config.mnc + "mnc");
+            }
+        }
+
+        if (!config.locale.getLanguage().isEmpty()) {
+            parts.add(localeToResourceQualifier(config.locale));
+        }
+
+        switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) {
+            case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR:
+                parts.add("ldltr");
+                break;
+            case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL:
+                parts.add("ldrtl");
+                break;
+            default:
+                break;
+        }
+
+        if (config.smallestScreenWidthDp != 0) {
+            parts.add("sw" + config.smallestScreenWidthDp + "dp");
+        }
+
+        if (config.screenWidthDp != 0) {
+            parts.add("w" + config.screenWidthDp + "dp");
+        }
+
+        if (config.screenHeightDp != 0) {
+            parts.add("h" + config.screenHeightDp + "dp");
+        }
+
+        switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) {
+            case Configuration.SCREENLAYOUT_SIZE_SMALL:
+                parts.add("small");
+                break;
+            case Configuration.SCREENLAYOUT_SIZE_NORMAL:
+                parts.add("normal");
+                break;
+            case Configuration.SCREENLAYOUT_SIZE_LARGE:
+                parts.add("large");
+                break;
+            case Configuration.SCREENLAYOUT_SIZE_XLARGE:
+                parts.add("xlarge");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) {
+            case Configuration.SCREENLAYOUT_LONG_YES:
+                parts.add("long");
+                break;
+            case Configuration.SCREENLAYOUT_LONG_NO:
+                parts.add("notlong");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.orientation) {
+            case Configuration.ORIENTATION_LANDSCAPE:
+                parts.add("land");
+                break;
+            case Configuration.ORIENTATION_PORTRAIT:
+                parts.add("port");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) {
+            case Configuration.UI_MODE_TYPE_APPLIANCE:
+                parts.add("appliance");
+                break;
+            case Configuration.UI_MODE_TYPE_DESK:
+                parts.add("desk");
+                break;
+            case Configuration.UI_MODE_TYPE_TELEVISION:
+                parts.add("television");
+                break;
+            case Configuration.UI_MODE_TYPE_CAR:
+                parts.add("car");
+                break;
+            case Configuration.UI_MODE_TYPE_WATCH:
+                parts.add("watch");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
+            case Configuration.UI_MODE_NIGHT_YES:
+                parts.add("night");
+                break;
+            case Configuration.UI_MODE_NIGHT_NO:
+                parts.add("notnight");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.densityDpi) {
+            case 0:
+                break;
+            case 120:
+                parts.add("ldpi");
+                break;
+            case 160:
+                parts.add("mdpi");
+                break;
+            case 213:
+                parts.add("tvdpi");
+                break;
+            case 240:
+                parts.add("hdpi");
+                break;
+            case 320:
+                parts.add("xhdpi");
+                break;
+            default:
+                parts.add(config.densityDpi + "dpi");
+                break;
+        }
+
+        switch (config.touchscreen) {
+            case Configuration.TOUCHSCREEN_NOTOUCH:
+                parts.add("notouch");
+                break;
+            case Configuration.TOUCHSCREEN_FINGER:
+                parts.add("finger");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.keyboardHidden) {
+            case Configuration.KEYBOARDHIDDEN_NO:
+                parts.add("keysexposed");
+                break;
+            case Configuration.KEYBOARDHIDDEN_YES:
+                parts.add("keyshidden");
+                break;
+            case Configuration.KEYBOARDHIDDEN_SOFT:
+                parts.add("keyssoft");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.keyboard) {
+            case Configuration.KEYBOARD_NOKEYS:
+                parts.add("nokeys");
+                break;
+            case Configuration.KEYBOARD_QWERTY:
+                parts.add("qwerty");
+                break;
+            case Configuration.KEYBOARD_12KEY:
+                parts.add("12key");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.navigationHidden) {
+            case Configuration.NAVIGATIONHIDDEN_NO:
+                parts.add("navexposed");
+                break;
+            case Configuration.NAVIGATIONHIDDEN_YES:
+                parts.add("navhidden");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.navigation) {
+            case Configuration.NAVIGATION_NONAV:
+                parts.add("nonav");
+                break;
+            case Configuration.NAVIGATION_DPAD:
+                parts.add("dpad");
+                break;
+            case Configuration.NAVIGATION_TRACKBALL:
+                parts.add("trackball");
+                break;
+            case Configuration.NAVIGATION_WHEEL:
+                parts.add("wheel");
+                break;
+            default:
+                break;
+        }
+
+        parts.add("v" + Build.VERSION.SDK_INT);
+        return TextUtils.join("-", parts);
+    }
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index c8de2f1..de2cc67 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -708,6 +708,7 @@
      * is generated if the direction of the 2-seconds window average gravity changed by at
      * least 35 degrees since the activation of the sensor. It is a wake up sensor.
      *
+     * @hide
      * @see #isWakeUpSensor()
      */
     public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41;
@@ -715,6 +716,7 @@
     /**
      * A constant string describing a wake up tilt detector sensor type.
      *
+     * @hide
      * @see #TYPE_WAKE_UP_TILT_DETECTOR
      */
     public static final String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR =
@@ -752,16 +754,47 @@
      */
     public static final int TYPE_ALL = -1;
 
-    /* Reporting mode constants for sensors. Each sensor will have exactly one
-       reporting mode associated with it. */
-    // Events are reported at a constant rate.
-    static int REPORTING_MODE_CONTINUOUS = 1;
+    // If this flag is set, the sensor defined as a wake up sensor. This field and REPORTING_MODE_*
+    // constants are defined as flags in sensors.h. Modify at both places if needed.
+    private static final int SENSOR_FLAG_WAKE_UP_SENSOR = 1;
 
-    // Events are reported only when the value changes.
-    static int REPORTING_MODE_ON_CHANGE = 2;
+    /**
+     * Events are reported at a constant rate which is set by the rate parameter of
+     * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}. Note: If other
+     * applications are requesting a higher rate, the sensor data might be delivered at faster rates
+     * than requested.
+     */
+    public static final int REPORTING_MODE_CONTINUOUS = 0;
 
-    // Upon detection of an event, the sensor deactivates itself and then sends a single event.
-    static int REPORTING_MODE_ONE_SHOT = 3;
+    /**
+     * Events are reported only when the value changes. Event delivery rate can be limited by
+     * setting appropriate value for rate parameter of
+     * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} Note: If other
+     * applications are requesting a higher rate, the sensor data might be delivered at faster rates
+     * than requested.
+     */
+    public static final int REPORTING_MODE_ON_CHANGE = 1;
+
+    /**
+     * Events are reported in one-shot mode. Upon detection of an event, the sensor deactivates
+     * itself and then sends a single event. Sensors of this reporting mode must be registered to
+     * using {@link SensorManager#requestTriggerSensor(TriggerEventListener, Sensor)}.
+     */
+    public static final int REPORTING_MODE_ONE_SHOT = 2;
+
+    /**
+     * Events are reported as described in the description of the sensor. The rate passed to
+     * registerListener might not have an impact on the rate of event delivery. See the sensor
+     * definition for more information on when and how frequently the events are reported. For
+     * example, step detectors report events when a step is detected.
+     *
+     * @see SensorManager#registerListener(SensorEventListener, Sensor, int, int)
+     */
+    public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3;
+
+    // Mask for the LSB 2nd, 3rd and fourth bits.
+    private static final int REPORTING_MODE_MASK = 0xE;
+    private static final int REPORTING_MODE_SHIFT = 1;
 
     // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
 
@@ -770,80 +803,74 @@
     // associated with
     // {@link SensorEvent} or {@link TriggerEvent} for the Sensor
     private static final int[] sSensorReportingModes = {
-            0, 0, // padding because sensor types start at 1
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_ACCELEROMETER
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GEOMAGNETIC_FIELD
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_ORIENTATION
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GYROSCOPE
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_LIGHT
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_PRESSURE
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_TEMPERATURE
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_PROXIMITY
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GRAVITY
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_LINEAR_ACCELERATION
-            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_ROTATION_VECTOR
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_RELATIVE_HUMIDITY
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_AMBIENT_TEMPERATURE
-            REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
-            REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_GAME_ROTATION_VECTOR
-            REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
-            REPORTING_MODE_ONE_SHOT,   1, // SENSOR_TYPE_SIGNIFICANT_MOTION
-            // added post 4.3
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_DETECTOR
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_COUNTER
-            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_HEART_RATE_MONITOR
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
+            0, // padding because sensor types start at 1
+            3, // SENSOR_TYPE_ACCELEROMETER
+            3, // SENSOR_TYPE_GEOMAGNETIC_FIELD
+            3, // SENSOR_TYPE_ORIENTATION
+            3, // SENSOR_TYPE_GYROSCOPE
+            3, // SENSOR_TYPE_LIGHT
+            3, // SENSOR_TYPE_PRESSURE
+            3, // SENSOR_TYPE_TEMPERATURE
+            3, // SENSOR_TYPE_PROXIMITY
+            3, // SENSOR_TYPE_GRAVITY
+            3, // SENSOR_TYPE_LINEAR_ACCELERATION
+            5, // SENSOR_TYPE_ROTATION_VECTOR
+            3, // SENSOR_TYPE_RELATIVE_HUMIDITY
+            3, // SENSOR_TYPE_AMBIENT_TEMPERATURE
+            6, // SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
+            4, // SENSOR_TYPE_GAME_ROTATION_VECTOR
+            6, // SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+            1, // SENSOR_TYPE_SIGNIFICANT_MOTION
+            1, // SENSOR_TYPE_STEP_DETECTOR
+            1, // SENSOR_TYPE_STEP_COUNTER
+            5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            1, // SENSOR_TYPE_HEART_RATE_MONITOR
+            3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
             // wake up variants of base sensors
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_WAKE_UP_LIGHT
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_PRESSURE
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GRAVITY
-            REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
-            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
-            REPORTING_MODE_ON_CHANGE,  3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
-            REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
-            REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
-            REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
-            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
-            REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
-            REPORTING_MODE_ONE_SHOT,   1, // SENSOR_TYPE_WAKE_GESTURE
+            3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
+            3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
+            3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
+            3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
+            3, // SENSOR_TYPE_WAKE_UP_LIGHT
+            3, // SENSOR_TYPE_WAKE_UP_PRESSURE
+            3, // SENSOR_TYPE_WAKE_UP_GRAVITY
+            3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
+            5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
+            3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
+            3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
+            6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
+            4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
+            6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
+            1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
+            1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
+            5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
+            1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
+            1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
+            1, // SENSOR_TYPE_WAKE_GESTURE
     };
 
-    static int getReportingMode(Sensor sensor) {
-        int offset = sensor.mType * 2;
-        if (offset >= sSensorReportingModes.length) {
-            // we don't know about this sensor, so this is probably a
-            // vendor-defined sensor, in that case, we figure out the reporting
-            // mode from the sensor meta-data.
-            int minDelay = sensor.mMinDelay;
-            if (minDelay == 0) {
-                return REPORTING_MODE_ON_CHANGE;
-            } else if (minDelay < 0) {
-                return REPORTING_MODE_ONE_SHOT;
-            } else {
-                return REPORTING_MODE_CONTINUOUS;
-            }
-        }
-        return sSensorReportingModes[offset];
+    /**
+     * Each sensor has exactly one reporting mode associated with it. This method returns the
+     * reporting mode constant for this sensor type.
+     *
+     * @return Reporting mode for the input sensor, one of REPORTING_MODE_* constants.
+     * @see #REPORTING_MODE_CONTINUOUS
+     * @see #REPORTING_MODE_ON_CHANGE
+     * @see #REPORTING_MODE_ONE_SHOT
+     * @see #REPORTING_MODE_SPECIAL_TRIGGER
+     */
+    public int getReportingMode() {
+        return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
     }
 
     static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
-        int type = sensor.mType;
         // RotationVector length has changed to 3 to 5 for API level 18
         // Set it to 3 for backward compatibility.
-        if (type == Sensor.TYPE_ROTATION_VECTOR &&
+        if (sensor.mType == Sensor.TYPE_ROTATION_VECTOR &&
                 sdkLevel <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             return 3;
         }
-        int offset = type * 2 + 1;
+        int offset = sensor.mType;
         if (offset >= sSensorReportingModes.length) {
             // we don't know about this sensor, so this is probably a
             // vendor-defined sensor, in that case, we don't know how many value
@@ -873,7 +900,7 @@
     private String  mStringType;
     private String  mRequiredPermission;
     private int     mMaxDelay;
-    private boolean mWakeUpSensor;
+    private int     mFlags;
 
     Sensor() {
     }
@@ -1016,7 +1043,7 @@
      * @return true if this is a wake up sensor, false otherwise.
      */
     public boolean isWakeUpSensor() {
-        return mWakeUpSensor;
+        return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
     }
 
     void setRange(float max, float res) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index b66ec86..a6c3ea4 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -99,7 +99,7 @@
             return false;
         }
         // Trigger Sensors should use the requestTriggerSensor call.
-        if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+        if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
             Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
             return false;
         }
@@ -133,7 +133,7 @@
     @Override
     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
         // Trigger Sensors should use the cancelTriggerSensor call.
-        if (sensor != null && Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+        if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
             return;
         }
 
@@ -159,7 +159,7 @@
     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
 
-        if (Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) return false;
+        if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
 
         synchronized (mTriggerListeners) {
             TriggerEventQueue queue = mTriggerListeners.get(listener);
@@ -181,7 +181,7 @@
     @Override
     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
             boolean disable) {
-        if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) {
+        if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
             return false;
         }
         synchronized (mTriggerListeners) {
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 5fd0f9b..d98bdc2 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -29,19 +29,19 @@
  *
  * <p>Creating a session is an expensive operation and can take several hundred milliseconds, since
  * it requires configuring the camera device's internal pipelines and allocating memory buffers for
- * sending images to the desired targets. While
- * {@link CameraDevice#createCaptureSession createCaptureSession} will provide a
- * CameraCaptureSession object immediately, configuration won't be complete until the
- * {@link CameraCaptureSession.StateListener#onConfigured onConfigured} callback is called for the
- * first time. If configuration cannot be completed, then the
+ * sending images to the desired targets. Therefore the setup is done asynchronously, and
+ * {@link CameraDevice#createCaptureSession createCaptureSession} will send the ready-to-use
+ * CameraCaptureSession to the provided listener's
+ * {@link CameraCaptureSession.StateListener#onConfigured onConfigured} callback. If configuration
+ * cannot be completed, then the
  * {@link CameraCaptureSession.StateListener#onConfigureFailed onConfigureFailed} is called, and the
  * session will not become active.</p>
- *
+ *<!--
  * <p>Any capture requests (repeating or non-repeating) submitted before the session is ready will
  * be queued up and will begin capture once the session becomes ready. In case the session cannot be
  * configured and {@link StateListener#onConfigureFailed onConfigureFailed} is called, all queued
  * capture requests are discarded.</p>
- *
+ *-->
  * <p>If a new session is created by the camera device, then the previous session is closed, and its
  * associated {@link StateListener#onClosed onClosed} callback will be invoked.  All
  * of the session methods will throw an IllegalStateException if called once the session is
@@ -166,10 +166,6 @@
      * capture request will be processed before any further repeating
      * requests are processed.<p>
      *
-     * <p>Repeating requests are a simple way for an application to maintain a
-     * preview or other continuous stream of frames, without having to submit
-     * requests through {@link #capture} at video rates.</p>
-     *
      * <p>To stop the repeating capture, call {@link #stopRepeating}. Calling
      * {@link #abortCaptures} will also clear the request.</p>
      *
@@ -323,7 +319,7 @@
      *
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
-     * @see #configureOutputs
+     * @see CameraDevice#createCaptureSession
      */
     public abstract void abortCaptures() throws CameraAccessException;
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 08cfc87..4a87680 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -30,7 +30,7 @@
  *
  * <p>These properties are fixed for a given CameraDevice, and can be queried
  * through the {@link CameraManager CameraManager}
- * interface in addition to through the CameraDevice interface.</p>
+ * interface with {@link CameraManager#getCameraCharacteristics}.</p>
  *
  * <p>{@link CameraCharacteristics} objects are immutable.</p>
  *
@@ -320,7 +320,7 @@
 
     /**
      * <p>List of frame rate ranges supported by the
-     * AE algorithm/hardware</p>
+     * auto-exposure (AE) algorithm/hardware</p>
      */
     public static final Key<android.util.Range<Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =
             new Key<android.util.Range<Integer>[]>("android.control.aeAvailableTargetFpsRanges", new TypeReference<android.util.Range<Integer>[]>() {{ }});
@@ -343,7 +343,7 @@
             new Key<Rational>("android.control.aeCompensationStep", Rational.class);
 
     /**
-     * <p>List of AF modes that can be
+     * <p>List of auto-focus (AF) modes that can be
      * selected with {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}.</p>
      * <p>Not all the auto-focus modes may be supported by a
      * given camera device. This entry lists the valid modes for
@@ -496,7 +496,7 @@
             new Key<int[]>("android.hotPixel.availableHotPixelModes", int[].class);
 
     /**
-     * <p>Supported resolutions for the JPEG thumbnail</p>
+     * <p>Supported resolutions for the JPEG thumbnail.</p>
      * <p>Below condiditions will be satisfied for this size list:</p>
      * <ul>
      * <li>The sizes will be sorted by increasing pixel area (width x height).
@@ -555,7 +555,7 @@
      * <p>List containing a subset of the optical image
      * stabilization (OIS) modes specified in
      * {@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}.</p>
-     * <p>If OIS is not implemented for a given camera device, this should
+     * <p>If OIS is not implemented for a given camera device, this will
      * contain only OFF.</p>
      *
      * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
@@ -612,7 +612,7 @@
 
     /**
      * <p>Direction the camera faces relative to
-     * device screen</p>
+     * device screen.</p>
      * @see #LENS_FACING_FRONT
      * @see #LENS_FACING_BACK
      */
@@ -622,7 +622,7 @@
     /**
      * <p>The set of noise reduction modes supported by this camera device.</p>
      * <p>This tag lists the valid modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}.</p>
-     * <p>Full-capability camera devices must laways support OFF and FAST.</p>
+     * <p>Full-capability camera devices must always support OFF and FAST.</p>
      *
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      */
@@ -778,17 +778,20 @@
             new Key<Byte>("android.request.pipelineMaxDepth", byte.class);
 
     /**
-     * <p>Optional. Defaults to 1. Defines how many sub-components
+     * <p>Defines how many sub-components
      * a result will be composed of.</p>
      * <p>In order to combat the pipeline latency, partial results
      * may be delivered to the application layer from the camera device as
      * soon as they are available.</p>
-     * <p>A value of 1 means that partial results are not supported.</p>
-     * <p>A typical use case for this might be: after requesting an AF lock the
-     * new AF state might be available 50% of the way through the pipeline.
-     * The camera device could then immediately dispatch this state via a
-     * partial result to the framework/application layer, and the rest of
-     * the metadata via later partial results.</p>
+     * <p>Optional; defaults to 1. A value of 1 means that partial
+     * results are not supported, and only the final TotalCaptureResult will
+     * be produced by the camera device.</p>
+     * <p>A typical use case for this might be: after requesting an
+     * auto-focus (AF) lock the new AF state might be available 50%
+     * of the way through the pipeline.  The camera device could
+     * then immediately dispatch this state via a partial result to
+     * the application, and the rest of the metadata via later
+     * partial results.</p>
      */
     public static final Key<Integer> REQUEST_PARTIAL_RESULT_COUNT =
             new Key<Integer>("android.request.partialResultCount", int.class);
@@ -805,8 +808,6 @@
      * to do this query each of android.request.availableRequestKeys,
      * android.request.availableResultKeys,
      * android.request.availableCharacteristicsKeys.</p>
-     * <p>XX: Maybe these should go into {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}
-     * as a table instead?</p>
      * <p>The following capabilities are guaranteed to be available on
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
      * <ul>
@@ -814,14 +815,11 @@
      * <li>MANUAL_POST_PROCESSING</li>
      * </ul>
      * <p>Other capabilities may be available on either FULL or LIMITED
-     * devices, but the app. should query this field to be sure.</p>
+     * devices, but the application should query this field to be sure.</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
-     * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
-     * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
      * @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
      */
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -837,7 +835,6 @@
      * at a more granular level than capabilities. This is especially
      * important for optional keys that are not listed under any capability
      * in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
-     * <p>TODO: This should be used by #getAvailableCaptureRequestKeys.</p>
      *
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @hide
@@ -862,7 +859,6 @@
      * at a more granular level than capabilities. This is especially
      * important for optional keys that are not listed under any capability
      * in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
-     * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
      *
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
@@ -878,7 +874,6 @@
      * android.request.availableResultKeys (except that it applies for
      * CameraCharacteristics instead of CaptureResult). See above for more
      * details.</p>
-     * <p>TODO: This should be used by CameraCharacteristics#getKeys.</p>
      * @hide
      */
     public static final Key<int[]> REQUEST_AVAILABLE_CHARACTERISTICS_KEYS =
@@ -926,10 +921,15 @@
             new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
 
     /**
-     * <p>The maximum ratio between active area width
-     * and crop region width, or between active area height and
-     * crop region height, if the crop region height is larger
-     * than width</p>
+     * <p>The maximum ratio between both active area width
+     * and crop region width, and active area height and
+     * crop region height.</p>
+     * <p>This represents the maximum amount of zooming possible by
+     * the camera device, or equivalently, the minimum cropping
+     * window size.</p>
+     * <p>Crop regions that have a width or height that is smaller
+     * than this ratio allows will be rounded up to the minimum
+     * allowed size by the camera device.</p>
      */
     public static final Key<Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM =
             new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
@@ -1326,15 +1326,21 @@
             new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
 
     /**
-     * <p>Range of valid sensitivities</p>
+     * <p>Range of valid sensitivities.</p>
+     * <p>The minimum and maximum valid values for the
+     * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} control.</p>
+     * <p>The values are the standard ISO sensitivity values,
+     * as defined in ISO 12232:2006.</p>
+     *
+     * @see CaptureRequest#SENSOR_SENSITIVITY
      */
     public static final Key<android.util.Range<Integer>> SENSOR_INFO_SENSITIVITY_RANGE =
             new Key<android.util.Range<Integer>>("android.sensor.info.sensitivityRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
-     * <p>Arrangement of color filters on sensor;
+     * <p>The arrangement of color filters on sensor;
      * represents the colors in the top-left 2x2 section of
-     * the sensor, in reading order</p>
+     * the sensor, in reading order.</p>
      * @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB
      * @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG
      * @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG
@@ -1372,8 +1378,11 @@
 
     /**
      * <p>The physical dimensions of the full pixel
-     * array</p>
-     * <p>Needed for FOV calculation for old API</p>
+     * array.</p>
+     * <p>This is the physical size of the sensor pixel
+     * array defined by {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
      */
     public static final Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE =
             new Key<android.util.SizeF>("android.sensor.info.physicalSize", android.util.SizeF.class);
@@ -1381,9 +1390,17 @@
     /**
      * <p>Dimensions of full pixel array, possibly
      * including black calibration pixels.</p>
-     * <p>Maximum output resolution for raw format must
-     * match this in
-     * android.scaler.availableStreamConfigurations.</p>
+     * <p>The pixel count of the full pixel array,
+     * which covers {@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize} area.</p>
+     * <p>If a camera device supports raw sensor formats, either this
+     * or {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is the maximum output
+     * raw size listed in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.
+     * If a size corresponding to pixelArraySize is listed, the resulting
+     * raw sensor image will include black pixels.</p>
+     *
+     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
      */
     public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
             new Key<android.util.Size>("android.sensor.info.pixelArraySize", android.util.Size.class);
@@ -1406,6 +1423,18 @@
             new Key<Integer>("android.sensor.info.whiteLevel", int.class);
 
     /**
+     * <p>The sensor timestamp calibration quality.</p>
+     * <p>The sensor timestamp calibration quality determines the reliability of
+     * {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} provided by the camera device.</p>
+     *
+     * @see CaptureResult#SENSOR_TIMESTAMP
+     * @see #SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED
+     * @see #SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED
+     */
+    public static final Key<Integer> SENSOR_INFO_TIMESTAMP_CALIBRATION =
+            new Key<Integer>("android.sensor.info.timestampCalibration", int.class);
+
+    /**
      * <p>The standard reference illuminant used as the scene light source when
      * calculating the {@link CameraCharacteristics#SENSOR_COLOR_TRANSFORM1 android.sensor.colorTransform1},
      * {@link CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1 android.sensor.calibrationTransform1}, and
@@ -1638,8 +1667,8 @@
             new Key<Integer>("android.sensor.orientation", 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>Lists the supported sensor test pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
+     * <p>Optional. Defaults to [OFF].</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
@@ -1648,10 +1677,9 @@
             new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
 
     /**
-     * <p>Which face detection modes are available,
-     * if any</p>
-     * <p>OFF means face detection is disabled, it must
-     * be included in the list.</p>
+     * <p>The face detection modes that are available
+     * for this camera device.</p>
+     * <p>OFF is always supported.</p>
      * <p>SIMPLE means the device supports the
      * android.statistics.faceRectangles and
      * android.statistics.faceScores outputs.</p>
@@ -1663,8 +1691,8 @@
             new Key<int[]>("android.statistics.info.availableFaceDetectModes", int[].class);
 
     /**
-     * <p>Maximum number of simultaneously detectable
-     * faces</p>
+     * <p>The maximum number of simultaneously detectable
+     * faces.</p>
      */
     public static final Key<Integer> STATISTICS_INFO_MAX_FACE_COUNT =
             new Key<Integer>("android.statistics.info.maxFaceCount", int.class);
@@ -1673,7 +1701,7 @@
      * <p>The set of hot pixel map output modes supported by this camera device.</p>
      * <p>This tag lists valid output modes for {@link CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE android.statistics.hotPixelMapMode}.</p>
      * <p>If no hotpixel map is available for this camera device, this will contain
-     * only OFF.  If the hotpixel map is available, this should include both
+     * only OFF.  If the hotpixel map is available, this will include both
      * the ON and OFF options.</p>
      *
      * @see CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index e9213c5..1f89d33 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -52,7 +52,7 @@
      * Create a request suitable for a camera preview window. Specifically, this
      * means that high frame rate is given priority over the highest-quality
      * post-processing. These requests would normally be used with the
-     * {@link #setRepeatingRequest} method.
+     * {@link CameraCaptureSession#setRepeatingRequest} method.
      *
      * @see #createCaptureRequest
      */
@@ -61,7 +61,7 @@
     /**
      * Create a request suitable for still image capture. Specifically, this
      * means prioritizing image quality over frame rate. These requests would
-     * commonly be used with the {@link #capture} method.
+     * commonly be used with the {@link CameraCaptureSession#capture} method.
      *
      * @see #createCaptureRequest
      */
@@ -71,7 +71,7 @@
      * Create a request suitable for video recording. Specifically, this means
      * that a stable frame rate is used, and post-processing is set for
      * recording quality. These requests would commonly be used with the
-     * {@link #setRepeatingRequest} method.
+     * {@link CameraCaptureSession#setRepeatingRequest} method.
      *
      * @see #createCaptureRequest
      */
@@ -81,8 +81,8 @@
      * Create a request suitable for still image capture while recording
      * video. Specifically, this means maximizing image quality without
      * disrupting the ongoing recording. These requests would commonly be used
-     * with the {@link #capture} method while a request based on
-     * {@link #TEMPLATE_RECORD} is is in use with {@link #setRepeatingRequest}.
+     * with the {@link CameraCaptureSession#capture} method while a request based on
+     * {@link #TEMPLATE_RECORD} is is in use with {@link CameraCaptureSession#setRepeatingRequest}.
      *
      * @see #createCaptureRequest
      */
@@ -132,116 +132,6 @@
     /**
      * <p>Set up a new output set of Surfaces for the camera device.</p>
      *
-     * <p>The configuration determines the set of potential output Surfaces for
-     * the camera device for each capture request. A given request may use all
-     * or a only some of the outputs. This method must be called before requests
-     * can be submitted to the camera with {@link #capture capture},
-     * {@link #captureBurst captureBurst},
-     * {@link #setRepeatingRequest setRepeatingRequest}, or
-     * {@link #setRepeatingBurst setRepeatingBurst}.</p>
-     *
-     * <p>Surfaces suitable for inclusion as a camera output can be created for
-     * various use cases and targets:</p>
-     *
-     * <ul>
-     *
-     * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set
-     *   the size of the Surface with
-     *   {@link android.view.SurfaceHolder#setFixedSize} to be one of the
-     *   supported
-     *   {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
-     *   before calling {@link android.view.SurfaceHolder#getSurface}.</li>
-     *
-     * <li>For accessing through an OpenGL texture via a
-     *   {@link android.graphics.SurfaceTexture SurfaceTexture}: Set the size of
-     *   the SurfaceTexture with
-     *   {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one
-     *   of the supported
-     *   {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
-     *   before creating a Surface from the SurfaceTexture with
-     *   {@link Surface#Surface}.</li>
-     *
-     * <li>For recording with {@link android.media.MediaCodec}: Call
-     *   {@link android.media.MediaCodec#createInputSurface} after configuring
-     *   the media codec to use one of the
-     *   {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
-     *   </li>
-     *
-     * <li>For recording with {@link android.media.MediaRecorder}: TODO</li>
-     *
-     * <li>For efficient YUV processing with {@link android.renderscript}:
-     *   Create a RenderScript
-     *   {@link android.renderscript.Allocation Allocation} with a supported YUV
-     *   type, the IO_INPUT flag, and one of the supported
-     *   {@link StreamConfigurationMap#getOutputSizes(int) processed sizes}. Then
-     *   obtain the Surface with
-     *   {@link android.renderscript.Allocation#getSurface}.</li>
-     *
-     * <li>For access to uncompressed or {@link ImageFormat#JPEG JPEG} data in the application:
-     * Create a {@link android.media.ImageReader} object with the desired
-     * {@link StreamConfigurationMap#getOutputFormats() image format}, and a size from the matching
-     * {@link StreamConfigurationMap#getOutputSizes(int) processed size} and {@code format}.
-     * Then obtain a {@link Surface} from it.</li>
-     * </ul>
-     *
-     * </p>
-     *
-     * <p>This function can take several hundred milliseconds to execute, since
-     * camera hardware may need to be powered on or reconfigured.</p>
-     *
-     * <p>The camera device will query each Surface's size and formats upon this
-     * call, so they must be set to a valid setting at this time (in particular:
-     * if the format is user-visible, it must be one of
-     * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
-     * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
-     *
-     * <p>When this method is called with valid Surfaces, the device will transition to the {@link
-     * StateListener#onBusy busy state}. Once configuration is complete, the device will transition
-     * into the {@link StateListener#onIdle idle state}. Capture requests using the newly-configured
-     * Surfaces may then be submitted with {@link #capture}, {@link #captureBurst}, {@link
-     * #setRepeatingRequest}, or {@link #setRepeatingBurst}.</p>
-     *
-     * <p>If this method is called while the camera device is still actively processing previously
-     * submitted captures, then the following sequence of events occurs: The device transitions to
-     * the busy state and calls the {@link StateListener#onBusy} callback. Second, if a repeating
-     * request is set it is cleared.  Third, the device finishes up all in-flight and pending
-     * requests. Finally, once the device is idle, it then reconfigures its outputs, and calls the
-     * {@link StateListener#onIdle} method once it is again ready to accept capture
-     * requests. Therefore, no submitted work is discarded. To idle as fast as possible, use {@link
-     * #flush} and wait for the idle callback before calling configureOutputs. This will discard
-     * work, but reaches the new configuration sooner.</p>
-     *
-     * <p>Using larger resolution outputs, or more outputs, can result in slower
-     * output rate from the device.</p>
-     *
-     * <p>Configuring the outputs with an empty or null list will transition the camera into an
-     * {@link StateListener#onUnconfigured unconfigured state} instead of the {@link
-     * StateListener#onIdle idle state}.  </p>
-     *
-     * <p>Calling configureOutputs with the same arguments as the last call to
-     * configureOutputs has no effect, and the {@link StateListener#onBusy busy}
-     * and {@link StateListener#onIdle idle} state transitions will happen
-     * immediately.</p>
-     *
-     * @param outputs The new set of Surfaces that should be made available as
-     * targets for captured image data.
-     *
-     * @throws IllegalArgumentException if the set of output Surfaces do not
-     * meet the requirements
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera device is not idle, or
-     *                               if the camera device has been closed
-     *
-     * @see StateListener#onBusy
-     * @see StateListener#onIdle
-     * @see StateListener#onActive
-     * @see StateListener#onUnconfigured
-     * @see #stopRepeating
-     * @see #flush
-     * @see StreamConfigurationMap#getOutputFormats()
-     * @see StreamConfigurationMap#getOutputSizes(int)
-     * @see StreamConfigurationMap#getOutputSizes(Class)
      * @deprecated Use {@link #createCaptureSession} instead
      */
     @Deprecated
@@ -264,10 +154,11 @@
      *
      * <ul>
      *
-     * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set the size of the
-     *   Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the sizes
-     *   returned by
-     *   {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceView.class)}
+     * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Once the SurfaceView's
+     *   Surface is {@link android.view.SurfaceHolder.Callback#surfaceCreated created}, set the
+     *   size of the Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the
+     *   sizes returned by
+     *   {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceHolder.class)}
      *   and then obtain the Surface by calling {@link android.view.SurfaceHolder#getSurface}.</li>
      *
      * <li>For accessing through an OpenGL texture via a
@@ -300,22 +191,18 @@
      *   Then obtain the Surface with
      *   {@link android.renderscript.Allocation#getSurface}.</li>
      *
-     * <li>For access to raw, uncompressed or JPEG data in the application: Create a
-     *   {@link android.media.ImageReader} object with the one of the supported
-     *   {@link StreamConfigurationMap#getOutputFormats() output image formats}, and a
-     *   size from the supported
-     *   {@link StreamConfigurationMap#getOutputSizes(int) sizes for that format}. Then obtain
-     *   a Surface from it with {@link android.media.ImageReader#getSurface}.</li>
+     * <li>For access to raw, uncompressed JPEG data in the application: Create an
+     *   {@link android.media.ImageReader} object with one of the supported output formats given by
+     *   {@link StreamConfigurationMap#getOutputFormats()}, setting its size to one of the
+     *   corresponding supported sizes by passing the chosen output format into
+     *   {@link StreamConfigurationMap#getOutputSizes(int)}. Then obtain a
+     *   {@link android.view.Surface} from it with {@link android.media.ImageReader#getSurface()}.
+     *   </li>
      *
      * </ul>
      *
-     * </p>
-     *
      * <p>The camera device will query each Surface's size and formats upon this
-     * call, so they must be set to a valid setting at this time (in particular:
-     * if the format is user-visible, it must be one of
-     * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
-     * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
+     * call, so they must be set to a valid setting at this time.</p>
      *
      * <p>It can take several hundred milliseconds for the session's configuration to complete,
      * since camera hardware may need to be powered on or reconfigured. Once the configuration is
@@ -342,10 +229,7 @@
      * @param listener The listener to notify about the status of the new capture session.
      * @param handler The handler on which the listener should be invoked, or {@code null} to use
      *                the current thread's {@link android.os.Looper looper}.
-     * <!--
-     * @return A new camera capture session to use, or null if an empty/null set of Surfaces is
-     *         provided.
-     * -->
+     *
      * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements,
      *                                  the listener is null, or the handler is null but the current
      *                                  thread has no looper.
@@ -393,92 +277,16 @@
     /**
      * <p>Submit a request for an image to be captured by this CameraDevice.</p>
      *
-     * <p>The request defines all the parameters for capturing the single image,
-     * including sensor, lens, flash, and post-processing settings.</p>
-     *
-     * <p>Each request will produce one {@link CaptureResult} and produce new
-     * frames for one or more target Surfaces, set with the CaptureRequest
-     * builder's {@link CaptureRequest.Builder#addTarget} method. The target
-     * surfaces must be configured as active outputs with
-     * {@link #configureOutputs} before calling this method.</p>
-     *
-     * <p>Multiple requests can be in progress at once. They are processed in
-     * first-in, first-out order, with minimal delays between each
-     * capture. Requests submitted through this method have higher priority than
-     * those submitted through {@link #setRepeatingRequest} or
-     * {@link #setRepeatingBurst}, and will be processed as soon as the current
-     * repeat/repeatBurst processing completes.</p>
-     *
-     * @param request the settings for this capture
-     * @param listener The callback object to notify once this request has been
-     * processed. If null, no metadata will be produced for this capture,
-     * although image data will still be produced.
-     * @param handler the handler on which the listener should be invoked, or
-     * {@code null} to use the current thread's {@link android.os.Looper
-     * looper}.
-     *
-     * @return int A unique capture sequence ID used by
-     *             {@link CaptureListener#onCaptureSequenceCompleted}.
-     *
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera is currently busy or unconfigured,
-     *                               or the camera device has been closed.
-     * @throws IllegalArgumentException If the request targets Surfaces not
-     * currently configured as outputs. Or if the handler is null, the listener
-     * is not null, and the calling thread has no looper.
-     *
-     * @see #captureBurst
-     * @see #setRepeatingRequest
-     * @see #setRepeatingBurst
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession#capture} instead
      */
     @Deprecated
     public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler)
             throws CameraAccessException;
 
     /**
-     * Submit a list of requests to be captured in sequence as a burst. The
-     * burst will be captured in the minimum amount of time possible, and will
-     * not be interleaved with requests submitted by other capture or repeat
-     * calls.
+     * Submit a list of requests to be captured in sequence as a burst.
      *
-     * <p>The requests will be captured in order, each capture producing one
-     * {@link CaptureResult} and image buffers for one or more target
-     * {@link android.view.Surface surfaces}. The target surfaces for each
-     * request (set with {@link CaptureRequest.Builder#addTarget}) must be
-     * configured as active outputs with {@link #configureOutputs} before
-     * calling this method.</p>
-     *
-     * <p>The main difference between this method and simply calling
-     * {@link #capture} repeatedly is that this method guarantees that no
-     * other requests will be interspersed with the burst.</p>
-     *
-     * @param requests the list of settings for this burst capture
-     * @param listener The callback object to notify each time one of the
-     * requests in the burst has been processed. If null, no metadata will be
-     * produced for any requests in this burst, although image data will still
-     * be produced.
-     * @param handler the handler on which the listener should be invoked, or
-     * {@code null} to use the current thread's {@link android.os.Looper
-     * looper}.
-     *
-     * @return int A unique capture sequence ID used by
-     *             {@link CaptureListener#onCaptureSequenceCompleted}.
-     *
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera is currently busy or unconfigured,
-     *                               or the camera device has been closed.
-     * @throws IllegalArgumentException If the requests target Surfaces not
-     * currently configured as outputs. Or if the handler is null, the listener
-     * is not null, and the calling thread has no looper. Or if no requests were
-     * passed in.
-     *
-     * @see #capture
-     * @see #setRepeatingRequest
-     * @see #setRepeatingBurst
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession#captureBurst} instead
      */
     @Deprecated
     public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
@@ -487,58 +295,7 @@
     /**
      * Request endlessly repeating capture of images by this CameraDevice.
      *
-     * <p>With this method, the CameraDevice will continually capture images
-     * using the settings in the provided {@link CaptureRequest}, at the maximum
-     * rate possible.</p>
-     *
-     * <p>Repeating requests are a simple way for an application to maintain a
-     * preview or other continuous stream of frames, without having to
-     * continually submit identical requests through {@link #capture}.</p>
-     *
-     * <p>Repeat requests have lower priority than those submitted
-     * through {@link #capture} or {@link #captureBurst}, so if
-     * {@link #capture} is called when a repeating request is active, the
-     * capture request will be processed before any further repeating
-     * requests are processed.<p>
-     *
-     * <p>Repeating requests are a simple way for an application to maintain a
-     * preview or other continuous stream of frames, without having to submit
-     * requests through {@link #capture} at video rates.</p>
-     *
-     * <p>To stop the repeating capture, call {@link #stopRepeating}. Calling
-     * {@link #flush} will also clear the request.</p>
-     *
-     * <p>Calling this method will replace any earlier repeating request or
-     * burst set up by this method or {@link #setRepeatingBurst}, although any
-     * in-progress burst will be completed before the new repeat request will be
-     * used.</p>
-     *
-     * @param request the request to repeat indefinitely
-     * @param listener The callback object to notify every time the
-     * request finishes processing. If null, no metadata will be
-     * produced for this stream of requests, although image data will
-     * still be produced.
-     * @param handler the handler on which the listener should be invoked, or
-     * {@code null} to use the current thread's {@link android.os.Looper
-     * looper}.
-     *
-     * @return int A unique capture sequence ID used by
-     *             {@link CaptureListener#onCaptureSequenceCompleted}.
-     *
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera is currently busy or unconfigured,
-     *                               or the camera device has been closed.
-     * @throws IllegalArgumentException If the requests reference Surfaces not
-     * currently configured as outputs. Or if the handler is null, the listener
-     * is not null, and the calling thread has no looper.
-     *
-     * @see #capture
-     * @see #captureBurst
-     * @see #setRepeatingBurst
-     * @see #stopRepeating
-     * @see #flush
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession#setRepeatingRequest} instead
      */
     @Deprecated
     public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
@@ -548,58 +305,7 @@
      * <p>Request endlessly repeating capture of a sequence of images by this
      * CameraDevice.</p>
      *
-     * <p>With this method, the CameraDevice will continually capture images,
-     * cycling through the settings in the provided list of
-     * {@link CaptureRequest CaptureRequests}, at the maximum rate possible.</p>
-     *
-     * <p>If a request is submitted through {@link #capture} or
-     * {@link #captureBurst}, the current repetition of the request list will be
-     * completed before the higher-priority request is handled. This guarantees
-     * that the application always receives a complete repeat burst captured in
-     * minimal time, instead of bursts interleaved with higher-priority
-     * captures, or incomplete captures.</p>
-     *
-     * <p>Repeating burst requests are a simple way for an application to
-     * maintain a preview or other continuous stream of frames where each
-     * request is different in a predicatable way, without having to continually
-     * submit requests through {@link #captureBurst} .</p>
-     *
-     * <p>To stop the repeating capture, call {@link #stopRepeating}. Any
-     * ongoing burst will still be completed, however. Calling
-     * {@link #flush} will also clear the request.</p>
-     *
-     * <p>Calling this method will replace a previously-set repeating request or
-     * burst set up by this method or {@link #setRepeatingRequest}, although any
-     * in-progress burst will be completed before the new repeat burst will be
-     * used.</p>
-     *
-     * @param requests the list of requests to cycle through indefinitely
-     * @param listener The callback object to notify each time one of the
-     * requests in the repeating bursts has finished processing. If null, no
-     * metadata will be produced for this stream of requests, although image
-     * data will still be produced.
-     * @param handler the handler on which the listener should be invoked, or
-     * {@code null} to use the current thread's {@link android.os.Looper
-     * looper}.
-     *
-     * @return int A unique capture sequence ID used by
-     *             {@link CaptureListener#onCaptureSequenceCompleted}.
-     *
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera is currently busy or unconfigured,
-     *                               or the camera device has been closed.
-     * @throws IllegalArgumentException If the requests reference Surfaces not
-     * currently configured as outputs. Or if the handler is null, the listener
-     * is not null, and the calling thread has no looper. Or if no requests were
-     * passed in.
-     *
-     * @see #capture
-     * @see #captureBurst
-     * @see #setRepeatingRequest
-     * @see #stopRepeating
-     * @see #flush
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession#setRepeatingBurst} instead
      */
     @Deprecated
     public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
@@ -608,24 +314,9 @@
     /**
      * <p>Cancel any ongoing repeating capture set by either
      * {@link #setRepeatingRequest setRepeatingRequest} or
-     * {@link #setRepeatingBurst}. Has no effect on requests submitted through
-     * {@link #capture capture} or {@link #captureBurst captureBurst}.</p>
+     * {@link #setRepeatingBurst}.
      *
-     * <p>Any currently in-flight captures will still complete, as will any
-     * burst that is mid-capture. To ensure that the device has finished
-     * processing all of its capture requests and is in idle state, wait for the
-     * {@link StateListener#onIdle} callback after calling this
-     * method..</p>
-     *
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera is currently busy or unconfigured,
-     *                               or the camera device has been closed.
-     *
-     * @see #setRepeatingRequest
-     * @see #setRepeatingBurst
-     * @see StateListener#onIdle
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession#stopRepeating} instead
      */
     @Deprecated
     public abstract void stopRepeating() throws CameraAccessException;
@@ -634,36 +325,7 @@
      * Flush all captures currently pending and in-progress as fast as
      * possible.
      *
-     * <p>The camera device will discard all of its current work as fast as
-     * possible. Some in-flight captures may complete successfully and call
-     * {@link CaptureListener#onCaptureCompleted}, while others will trigger
-     * their {@link CaptureListener#onCaptureFailed} callbacks. If a repeating
-     * request or a repeating burst is set, it will be cleared by the flush.</p>
-     *
-     * <p>This method is the fastest way to idle the camera device for
-     * reconfiguration with {@link #configureOutputs}, at the cost of discarding
-     * in-progress work. Once the flush is complete, the idle callback will be
-     * called.</p>
-     *
-     * <p>Flushing will introduce at least a brief pause in the stream of data
-     * from the camera device, since once the flush is complete, the first new
-     * request has to make it through the entire camera pipeline before new
-     * output buffers are produced.</p>
-     *
-     * <p>This means that using {@code flush()} to simply remove pending
-     * requests is not recommended; it's best used for quickly switching output
-     * configurations, or for cancelling long in-progress requests (such as a
-     * multi-second capture).</p>
-     *
-     * @throws CameraAccessException if the camera device is no longer connected or has
-     *                               encountered a fatal error
-     * @throws IllegalStateException if the camera is not idle/active,
-     *                               or the camera device has been closed.
-     *
-     * @see #setRepeatingRequest
-     * @see #setRepeatingBurst
-     * @see #configureOutputs
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession#abortCaptures} instead
      */
     @Deprecated
     public abstract void flush() throws CameraAccessException;
@@ -690,15 +352,7 @@
      * <p>A listener for tracking the progress of a {@link CaptureRequest}
      * submitted to the camera device.</p>
      *
-     * <p>This listener is called when a request triggers a capture to start,
-     * and when the capture is complete. In case on an error capturing an image,
-     * the error method is triggered instead of the completion method.</p>
-     *
-     * @see #capture
-     * @see #captureBurst
-     * @see #setRepeatingRequest
-     * @see #setRepeatingBurst
-     * @deprecated Use {@link CameraCaptureSession} instead
+     * @deprecated Use {@link CameraCaptureSession.CaptureListener} instead
      */
     @Deprecated
     public static abstract class CaptureListener {
@@ -715,29 +369,6 @@
          * This method is called when the camera device has started capturing
          * the output image for the request, at the beginning of image exposure.
          *
-         * <p>This callback is invoked right as the capture of a frame begins,
-         * so it is the most appropriate time for playing a shutter sound,
-         * or triggering UI indicators of capture.</p>
-         *
-         * <p>The request that is being used for this capture is provided, along
-         * with the actual timestamp for the start of exposure. This timestamp
-         * matches the timestamp that will be included in
-         * {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field},
-         * and in the buffers sent to each output Surface. These buffer
-         * timestamps are accessible through, for example,
-         * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or
-         * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p>
-         *
-         * <p>For the simplest way to play a shutter sound camera shutter or a
-         * video recording start/stop sound, see the
-         * {@link android.media.MediaActionSound} class.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera the CameraDevice sending the callback
-         * @param request the request for the capture that just begun
-         * @param timestamp the timestamp at start of capture, in nanoseconds.
-         *
          * @see android.media.MediaActionSound
          */
         public void onCaptureStarted(CameraDevice camera,
@@ -749,25 +380,6 @@
          * This method is called when some results from an image capture are
          * available.
          *
-         * <p>The result provided here will contain some subset of the fields of
-         * a full result. Multiple onCapturePartial calls may happen per
-         * capture; a given result field will only be present in one partial
-         * capture at most. The final onCaptureCompleted call will always
-         * contain all the fields, whether onCapturePartial was called or
-         * not.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera The CameraDevice sending the callback.
-         * @param request The request that was given to the CameraDevice
-         * @param result The partial output metadata from the capture, which
-         * includes a subset of the CaptureResult fields.
-         *
-         * @see #capture
-         * @see #captureBurst
-         * @see #setRepeatingRequest
-         * @see #setRepeatingBurst
-         *
          * @hide
          */
         public void onCapturePartial(CameraDevice camera,
@@ -779,37 +391,6 @@
          * This method is called when an image capture makes partial forward progress; some
          * (but not all) results from an image capture are available.
          *
-         * <p>The result provided here will contain some subset of the fields of
-         * a full result. Multiple {@link #onCaptureProgressed} calls may happen per
-         * capture; a given result field will only be present in one partial
-         * capture at most. The final {@link #onCaptureCompleted} call will always
-         * contain all the fields (in particular, the union of all the fields of all
-         * the partial results composing the total result).</p>
-         *
-         * <p>For each request, some result data might be available earlier than others. The typical
-         * delay between each partial result (per request) is a single frame interval.
-         * For performance-oriented use-cases, applications should query the metadata they need
-         * to make forward progress from the partial results and avoid waiting for the completed
-         * result.</p>
-         *
-         * <p>Each request will generate at least {@code 1} partial results, and at most
-         * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
-         *
-         * <p>Depending on the request settings, the number of partial results per request
-         * will vary, although typically the partial count could be the same as long as the
-         * camera device subsystems enabled stay the same.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera The CameraDevice sending the callback.
-         * @param request The request that was given to the CameraDevice
-         * @param partialResult The partial output metadata from the capture, which
-         * includes a subset of the {@link TotalCaptureResult} fields.
-         *
-         * @see #capture
-         * @see #captureBurst
-         * @see #setRepeatingRequest
-         * @see #setRepeatingBurst
          */
         public void onCaptureProgressed(CameraDevice camera,
                 CaptureRequest request, CaptureResult partialResult) {
@@ -819,26 +400,6 @@
         /**
          * This method is called when an image capture has fully completed and all the
          * result metadata is available.
-         *
-         * <p>This callback will always fire after the last {@link #onCaptureProgressed};
-         * in other words, no more partial results will be delivered once the completed result
-         * is available.</p>
-         *
-         * <p>For performance-intensive use-cases where latency is a factor, consider
-         * using {@link #onCaptureProgressed} instead.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera The CameraDevice sending the callback.
-         * @param request The request that was given to the CameraDevice
-         * @param result The total output metadata from the capture, including the
-         * final capture parameters and the state of the camera system during
-         * capture.
-         *
-         * @see #capture
-         * @see #captureBurst
-         * @see #setRepeatingRequest
-         * @see #setRepeatingBurst
          */
         public void onCaptureCompleted(CameraDevice camera,
                 CaptureRequest request, TotalCaptureResult result) {
@@ -849,29 +410,6 @@
          * This method is called instead of {@link #onCaptureCompleted} when the
          * camera device failed to produce a {@link CaptureResult} for the
          * request.
-         *
-         * <p>Other requests are unaffected, and some or all image buffers from
-         * the capture may have been pushed to their respective output
-         * streams.</p>
-         *
-         * <p>Some partial results may have been delivered before the capture fails;
-         * however after this callback fires, no more partial results will be delivered by
-         * {@link #onCaptureProgressed}.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera
-         *            The CameraDevice sending the callback.
-         * @param request
-         *            The request that was given to the CameraDevice
-         * @param failure
-         *            The output failure from the capture, including the failure reason
-         *            and the frame number.
-         *
-         * @see #capture
-         * @see #captureBurst
-         * @see #setRepeatingRequest
-         * @see #setRepeatingBurst
          */
         public void onCaptureFailed(CameraDevice camera,
                 CaptureRequest request, CaptureFailure failure) {
@@ -882,26 +420,6 @@
          * This method is called independently of the others in CaptureListener,
          * when a capture sequence finishes and all {@link CaptureResult}
          * or {@link CaptureFailure} for it have been returned via this listener.
-         *
-         * <p>In total, there will be at least one result/failure returned by this listener
-         * before this callback is invoked. If the capture sequence is aborted before any
-         * requests have been processed, {@link #onCaptureSequenceAborted} is invoked instead.</p>
-         *
-         * <p>The default implementation does nothing.</p>
-         *
-         * @param camera
-         *            The CameraDevice sending the callback.
-         * @param sequenceId
-         *            A sequence ID returned by the {@link #capture} family of functions.
-         * @param frameNumber
-         *            The last frame number (returned by {@link CaptureResult#getFrameNumber}
-         *            or {@link CaptureFailure#getFrameNumber}) in the capture sequence.
-         *
-         * @see CaptureResult#getFrameNumber()
-         * @see CaptureFailure#getFrameNumber()
-         * @see CaptureResult#getSequenceId()
-         * @see CaptureFailure#getSequenceId()
-         * @see #onCaptureSequenceAborted
          */
         public void onCaptureSequenceCompleted(CameraDevice camera,
                 int sequenceId, long frameNumber) {
@@ -912,25 +430,6 @@
          * This method is called independently of the others in CaptureListener,
          * when a capture sequence aborts before any {@link CaptureResult}
          * or {@link CaptureFailure} for it have been returned via this listener.
-         *
-         * <p>Due to the asynchronous nature of the camera device, not all submitted captures
-         * are immediately processed. It is possible to clear out the pending requests
-         * by a variety of operations such as {@link CameraDevice#stopRepeating} or
-         * {@link CameraDevice#flush}. When such an event happens,
-         * {@link #onCaptureSequenceCompleted} will not be called.</p>
-         *
-         * <p>The default implementation does nothing.</p>
-         *
-         * @param camera
-         *            The CameraDevice sending the callback.
-         * @param sequenceId
-         *            A sequence ID returned by the {@link #capture} family of functions.
-         *
-         * @see CaptureResult#getFrameNumber()
-         * @see CaptureFailure#getFrameNumber()
-         * @see CaptureResult#getSequenceId()
-         * @see CaptureFailure#getSequenceId()
-         * @see #onCaptureSequenceCompleted
          */
         public void onCaptureSequenceAborted(CameraDevice camera,
                 int sequenceId) {
@@ -945,14 +444,14 @@
      * <p>A listener must be provided to the {@link CameraManager#openCamera}
      * method to open a camera device.</p>
      *
-     * <p>These events include notifications about the device becoming idle (
-     * allowing for {@link #configureOutputs} to be called), about device
-     * disconnection, and about unexpected device errors.</p>
+     * <p>These events include notifications about the device completing startup (
+     * allowing for {@link #createCaptureSession} to be called), about device
+     * disconnection or closure, and about unexpected device errors.</p>
      *
-     * <p>Events about the progress of specific {@link CaptureRequest
-     * CaptureRequests} are provided through a {@link CaptureListener} given to
-     * the {@link #capture}, {@link #captureBurst}, {@link
-     * #setRepeatingRequest}, or {@link #setRepeatingBurst} methods.
+     * <p>Events about the progress of specific {@link CaptureRequest CaptureRequests} are provided
+     * through a {@link CameraCaptureSession.CaptureListener} given to the
+     * {@link CameraCaptureSession#capture}, {@link CameraCaptureSession#captureBurst},
+     * {@link CameraCaptureSession#setRepeatingRequest}, or {@link CameraCaptureSession#setRepeatingBurst} methods.
      *
      * @see CameraManager#openCamera
      */
@@ -1026,8 +525,9 @@
         /**
          * The method called when a camera device has finished opening.
          *
-         * <p>An opened camera will immediately afterwards transition into
-         * {@link #onUnconfigured}.</p>
+         * <p>At this point, the camera device is ready to use, and
+         * {@link CameraDevice#createCaptureSession} can be called to set up the first capture
+         * session.</p>
          *
          * @param camera the camera device that has become opened
          */
@@ -1036,21 +536,7 @@
         /**
          * The method called when a camera device has no outputs configured.
          *
-         * <p>An unconfigured camera device needs to be configured with
-         * {@link CameraDevice#configureOutputs} before being able to
-         * submit any capture request.</p>
-         *
-         * <p>This state may be entered by a newly opened camera or by
-         * calling {@link CameraDevice#configureOutputs} with a null/empty
-         * list of Surfaces when idle.</p>
-         *
-         * <p>Any attempts to submit a capture request while in this state
-         * will result in an {@link IllegalStateException} being thrown.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera the camera device has that become unconfigured
-         * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+         * @deprecated Use {@link #onOpened} instead.
          */
         @Deprecated
         public void onUnconfigured(CameraDevice camera) {
@@ -1061,27 +547,7 @@
          * The method called when a camera device begins processing
          * {@link CaptureRequest capture requests}.
          *
-         * <p>A camera may not be re-configured while in this state. The camera
-         * will transition to the idle state once all pending captures have
-         * completed. If a repeating request is set, the camera will remain active
-         * until it is cleared and the remaining requests finish processing. To
-         * transition to the idle state as quickly as possible, call {@link #flush()},
-         * which will idle the camera device as quickly as possible, likely canceling
-         * most in-progress captures.</p>
-         *
-         * <p>All calls except for {@link CameraDevice#configureOutputs} are
-         * legal while in this state.
-         * </p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera the camera device that has become active
-         *
-         * @see CameraDevice#capture
-         * @see CameraDevice#captureBurst
-         * @see CameraDevice#setRepeatingBurst
-         * @see CameraDevice#setRepeatingRequest
-         * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+         * @deprecated Use {@link CameraCaptureSession.StateListener#onActive} instead.
          */
         @Deprecated
         public void onActive(CameraDevice camera) {
@@ -1091,32 +557,7 @@
         /**
          * The method called when a camera device is busy.
          *
-         * <p>A camera becomes busy while it's outputs are being configured
-         * (after a call to {@link CameraDevice#configureOutputs} or while it's
-         * being flushed (after a call to {@link CameraDevice#flush}.</p>
-         *
-         * <p>Once the on-going operations are complete, the camera will automatically
-         * transition into {@link #onIdle} if there is at least one configured output,
-         * or {@link #onUnconfigured} otherwise.</p>
-         *
-         * <p>Any attempts to manipulate the camera while its is busy
-         * will result in an {@link IllegalStateException} being thrown.</p>
-         *
-         * <p>Only the following methods are valid to call while in this state:
-         * <ul>
-         * <li>{@link CameraDevice#getId}</li>
-         * <li>{@link CameraDevice#createCaptureRequest}</li>
-         * <li>{@link CameraDevice#close}</li>
-         * </ul>
-         * </p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera the camera device that has become busy
-         *
-         * @see CameraDevice#configureOutputs
-         * @see CameraDevice#flush
-         * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+         * @deprecated Use {@link CameraCaptureSession.StateListener#onConfigured} instead.
          */
         @Deprecated
         public void onBusy(CameraDevice camera) {
@@ -1142,30 +583,7 @@
          * The method called when a camera device has finished processing all
          * submitted capture requests and has reached an idle state.
          *
-         * <p>An idle camera device can have its outputs changed by calling {@link
-         * CameraDevice#configureOutputs}, which will transition it into the busy state.</p>
-         *
-         * <p>To idle and reconfigure outputs without canceling any submitted
-         * capture requests, the application needs to clear its repeating
-         * request/burst, if set, with {@link CameraDevice#stopRepeating}, and
-         * then wait for this callback to be called before calling {@link
-         * CameraDevice#configureOutputs}.</p>
-         *
-         * <p>To idle and reconfigure a camera device as fast as possible, the
-         * {@link CameraDevice#flush} method can be used, which will discard all
-         * pending and in-progress capture requests. Once the {@link
-         * CameraDevice#flush} method is called, the application must wait for
-         * this callback to fire before calling {@link
-         * CameraDevice#configureOutputs}.</p>
-         *
-         * <p>The default implementation of this method does nothing.</p>
-         *
-         * @param camera the camera device that has become idle
-         *
-         * @see CameraDevice#configureOutputs
-         * @see CameraDevice#stopRepeating
-         * @see CameraDevice#flush
-         * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+         * @deprecated Use {@link CameraCaptureSession.StateListener#onReady} instead.
          */
         @Deprecated
         public void onIdle(CameraDevice camera) {
@@ -1221,7 +639,7 @@
          *
          * @param camera The device reporting the error
          * @param error The error code, one of the
-         *     {@code CameraDeviceListener.ERROR_*} values.
+         *     {@code StateListener.ERROR_*} values.
          *
          * @see #ERROR_CAMERA_DEVICE
          * @see #ERROR_CAMERA_SERVICE
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7c0f37e6..0901562 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -35,7 +35,7 @@
 import java.util.ArrayList;
 
 /**
- * <p>An interface for iterating, listing, and connecting to
+ * <p>A system service manager for detecting, characterizing, and connecting to
  * {@link CameraDevice CameraDevices}.</p>
  *
  * <p>You can get an instance of this class by calling
@@ -357,14 +357,18 @@
     }
 
     /**
-     * Interface for listening to camera devices becoming available or
-     * unavailable.
+     * A listener for camera devices becoming available or
+     * unavailable to open.
      *
      * <p>Cameras become available when they are no longer in use, or when a new
      * removable camera is connected. They become unavailable when some
      * application or service starts using a camera, or when a removable camera
      * is disconnected.</p>
      *
+     * <p>Extend this listener and pass an instance of the subclass to
+     * {@link CameraManager#addAvailabilityListener} to be notified of such availability
+     * changes.</p>
+     *
      * @see addAvailabilityListener
      */
     public static abstract class AvailabilityListener {
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 94a5a79..5a02435 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -157,8 +157,8 @@
 
     /**
      * <p>The lens focus distance is not accurate, and the units used for
-     * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.
-     * Setting the lens to the same focus distance on separate occasions may
+     * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.</p>
+     * <p>Setting the lens to the same focus distance on separate occasions may
      * result in a different real focus distance, depending on factors such
      * as the orientation of the device, the age of the focusing mechanism,
      * and the device temperature. The focus distance value will still be
@@ -172,20 +172,24 @@
     public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0;
 
     /**
-     * <p>The lens focus distance is measured in diopters. However, setting the lens
-     * to the same focus distance on separate occasions may result in a
-     * different real focus distance, depending on factors such as the
-     * orientation of the device, the age of the focusing mechanism, and
-     * the device temperature.</p>
+     * <p>The lens focus distance is measured in diopters.</p>
+     * <p>However, setting the lens to the same focus distance
+     * on separate occasions may result in a different real
+     * focus distance, depending on factors such as the
+     * orientation of the device, the age of the focusing
+     * mechanism, and the device temperature.</p>
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
      */
     public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1;
 
     /**
-     * <p>The lens focus distance is measured in diopters. The lens mechanism is
-     * calibrated so that setting the same focus distance is repeatable on
-     * multiple occasions with good accuracy, and the focus distance corresponds
-     * to the real physical distance to the plane of best focus.</p>
+     * <p>The lens focus distance is measured in diopters, and
+     * is calibrated.</p>
+     * <p>The lens mechanism is calibrated so that setting the
+     * same focus distance is repeatable on multiple
+     * occasions with good accuracy, and the focus distance
+     * corresponds to the real physical distance to the plane
+     * of best focus.</p>
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
      */
     public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2;
@@ -195,11 +199,13 @@
     //
 
     /**
+     * <p>The camera device faces the same direction as the device's screen.</p>
      * @see CameraCharacteristics#LENS_FACING
      */
     public static final int LENS_FACING_FRONT = 0;
 
     /**
+     * <p>The camera device faces the opposite direction as the device's screen.</p>
      * @see CameraCharacteristics#LENS_FACING
      */
     public static final int LENS_FACING_BACK = 1;
@@ -215,11 +221,10 @@
      * <p>The full set of features supported by this capability makes
      * the camera2 api backwards compatible with the camera1
      * (android.hardware.Camera) API.</p>
-     * <p>TODO: @hide this. Doesn't really mean anything except
-     * act as a catch-all for all the 'base' functionality.</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @hide
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0;
 
@@ -228,15 +233,14 @@
      * tags or functionality not encapsulated by one of the other
      * capabilities.</p>
      * <p>A typical example is all tags marked 'optional'.</p>
-     * <p>TODO: @hide. We may not need this if we @hide all the optional
-     * tags not belonging to a capability.</p>
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @hide
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL = 1;
 
     /**
      * <p>The camera device can be manually controlled (3A algorithms such
-     * as auto exposure, and auto focus can be bypassed).
+     * as auto-exposure, and auto-focus can be bypassed).
      * The camera device supports basic manual control of the sensor image
      * acquisition related stages. This means the following controls are
      * guaranteed to be supported:</p>
@@ -257,11 +261,11 @@
      * <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
      * </ul>
      * </li>
-     * <li>Manual lens control<ul>
+     * <li>Manual lens control (if the lens is adjustable)<ul>
      * <li>android.lens.*</li>
      * </ul>
      * </li>
-     * <li>Manual flash control<ul>
+     * <li>Manual flash control (if a flash unit is present)<ul>
      * <li>android.flash.*</li>
      * </ul>
      * </li>
@@ -312,8 +316,6 @@
      * </ul>
      * <p>If auto white balance is enabled, then the camera device
      * will accurately report the values applied by AWB in the result.</p>
-     * <p>The camera device will also support everything in MANUAL_SENSOR
-     * except manual lens control and manual flash control.</p>
      * <p>A given camera device may also support additional post-processing
      * controls, but this capability only covers the above list of controls.</p>
      *
@@ -340,8 +342,8 @@
      * (both input/output) will match the maximum available
      * resolution of JPEG streams.</li>
      * </ul>
-     * <p>@hide this, TODO: remove it when input related APIs are ready.</p>
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @hide
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
 
@@ -355,12 +357,14 @@
      * <li>RAW16 is reprocessable into both YUV_420_888 and JPEG
      * formats.</li>
      * <li>The maximum available resolution for RAW16 streams (both
-     * input/output) will match the value in
-     * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</li>
+     * input/output) will match either the value in
+     * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li>
      * <li>All DNG-related optional metadata entries are provided
      * by the camera device.</li>
      * </ul>
      *
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
@@ -371,13 +375,13 @@
     //
 
     /**
-     * <p>The camera device will only support centered crop regions.</p>
+     * <p>The camera device only supports centered crop regions.</p>
      * @see CameraCharacteristics#SCALER_CROPPING_TYPE
      */
     public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0;
 
     /**
-     * <p>The camera device will support arbitrarily chosen crop regions.</p>
+     * <p>The camera device supports arbitrarily chosen crop regions.</p>
      * @see CameraCharacteristics#SCALER_CROPPING_TYPE
      */
     public static final int SCALER_CROPPING_TYPE_FREEFORM = 1;
@@ -415,6 +419,33 @@
     public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4;
 
     //
+    // Enumeration values for CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+    //
+
+    /**
+     * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in nanoseconds and monotonic,
+     * but can not be compared to timestamps from other subsystems
+     * (e.g. accelerometer, gyro etc.), or other instances of the same or different
+     * camera devices in the same system. Timestamps between streams and results for
+     * a single camera instance are comparable, and the timestamps for all buffers
+     * and the result metadata generated by a single capture are identical.</p>
+     *
+     * @see CaptureResult#SENSOR_TIMESTAMP
+     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+     */
+    public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED = 0;
+
+    /**
+     * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in the same timebase as
+     * android.os.SystemClock#elapsedRealtimeNanos(),
+     * and they can be compared to other timestamps using that base.</p>
+     *
+     * @see CaptureResult#SENSOR_TIMESTAMP
+     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+     */
+    public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED = 1;
+
+    //
     // Enumeration values for CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
     //
 
@@ -523,7 +554,7 @@
     //
 
     /**
-     * <p>android.led.transmit control is used</p>
+     * <p>android.led.transmit control is used.</p>
      * @see CameraCharacteristics#LED_AVAILABLE_LEDS
      * @hide
      */
@@ -534,11 +565,14 @@
     //
 
     /**
+     * <p>This camera device has only limited capabilities.</p>
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
 
     /**
+     * <p>This camera device is capable of supporting advanced imaging
+     * applications.</p>
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
@@ -548,9 +582,9 @@
     //
 
     /**
-     * <p>Every frame has the requests immediately applied.
-     * (and furthermore for all results,
-     * <code>android.sync.frameNumber == android.request.frameCount</code>)</p>
+     * <p>Every frame has the requests immediately applied.</p>
+     * <p>Furthermore for all results,
+     * <code>android.sync.frameNumber == android.request.frameCount</code></p>
      * <p>Changing controls over multiple requests one after another will
      * produce results that have those controls applied atomically
      * each frame.</p>
@@ -590,8 +624,8 @@
     public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0;
 
     /**
-     * <p>Must not slow down capture rate relative to sensor raw
-     * output.</p>
+     * <p>Color correction processing must not slow down
+     * capture rate relative to sensor raw output.</p>
      * <p>Advanced white balance adjustments above and beyond
      * the specified white balance pipeline may be applied.</p>
      * <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -604,8 +638,9 @@
     public static final int COLOR_CORRECTION_MODE_FAST = 1;
 
     /**
-     * <p>Capture rate (relative to sensor raw output)
-     * may be reduced by high quality.</p>
+     * <p>Color correction processing operates at improved
+     * quality but reduced capture rate (relative to sensor raw
+     * output).</p>
      * <p>Advanced white balance adjustments above and beyond
      * the specified white balance pipeline may be applied.</p>
      * <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -656,8 +691,8 @@
     //
 
     /**
-     * <p>The camera device's autoexposure routine is disabled;
-     * the application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
+     * <p>The camera device's autoexposure routine is disabled.</p>
+     * <p>The application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
      * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} and
      * {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are used by the camera
      * device, along with android.flash.* fields, if there's
@@ -672,7 +707,8 @@
 
     /**
      * <p>The camera device's autoexposure routine is active,
-     * with no flash control. The application's values for
+     * with no flash control.</p>
+     * <p>The application's values for
      * {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
      * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and
      * {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are ignored. The
@@ -689,10 +725,10 @@
     /**
      * <p>Like ON, except that the camera device also controls
      * the camera's flash unit, firing it in low-light
-     * conditions. The flash may be fired during a
-     * precapture sequence (triggered by
-     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and may be fired
-     * for captures for which the
+     * conditions.</p>
+     * <p>The flash may be fired during a precapture sequence
+     * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+     * may be fired for captures for which the
      * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
      * STILL_CAPTURE</p>
      *
@@ -705,10 +741,10 @@
     /**
      * <p>Like ON, except that the camera device also controls
      * the camera's flash unit, always firing it for still
-     * captures. The flash may be fired during a precapture
-     * sequence (triggered by
-     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and will always
-     * be fired for captures for which the
+     * captures.</p>
+     * <p>The flash may be fired during a precapture sequence
+     * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+     * will always be fired for captures for which the
      * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
      * STILL_CAPTURE</p>
      *
@@ -720,9 +756,10 @@
 
     /**
      * <p>Like ON_AUTO_FLASH, but with automatic red eye
-     * reduction. If deemed necessary by the camera device,
-     * a red eye reduction flash will fire during the
-     * precapture sequence.</p>
+     * reduction.</p>
+     * <p>If deemed necessary by the camera device, a red eye
+     * reduction flash will fire during the precapture
+     * sequence.</p>
      * @see CaptureRequest#CONTROL_AE_MODE
      */
     public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
@@ -739,8 +776,9 @@
 
     /**
      * <p>The precapture metering sequence will be started
-     * by the camera device. The exact effect of the precapture
-     * trigger depends on the current AE mode and state.</p>
+     * by the camera device.</p>
+     * <p>The exact effect of the precapture trigger depends on
+     * the current AE mode and state.</p>
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      */
     public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
@@ -752,7 +790,7 @@
     /**
      * <p>The auto-focus routine does not control the lens;
      * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} is controlled by the
-     * application</p>
+     * application.</p>
      *
      * @see CaptureRequest#LENS_FOCUS_DISTANCE
      * @see CaptureRequest#CONTROL_AF_MODE
@@ -760,12 +798,14 @@
     public static final int CONTROL_AF_MODE_OFF = 0;
 
     /**
-     * <p>If lens is not fixed focus.</p>
-     * <p>Use {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} to determine if lens
-     * is fixed-focus. In this mode, the lens does not move unless
+     * <p>Basic automatic focus mode.</p>
+     * <p>In this mode, the lens does not move unless
      * the autofocus trigger action is called. When that trigger
-     * is activated, AF must transition to ACTIVE_SCAN, then to
+     * is activated, AF will transition to ACTIVE_SCAN, then to
      * the outcome of the scan (FOCUSED or NOT_FOCUSED).</p>
+     * <p>Always supported if lens is not fixed focus.</p>
+     * <p>Use {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} to determine if lens
+     * is fixed-focus.</p>
      * <p>Triggering AF_CANCEL resets the lens position to default,
      * and sets the AF state to INACTIVE.</p>
      *
@@ -775,11 +815,16 @@
     public static final int CONTROL_AF_MODE_AUTO = 1;
 
     /**
+     * <p>Close-up focusing mode.</p>
      * <p>In this mode, the lens does not move unless the
-     * autofocus trigger action is called.</p>
-     * <p>When that trigger is activated, AF must transition to
+     * autofocus trigger action is called. When that trigger is
+     * activated, AF will transition to ACTIVE_SCAN, then to
+     * the outcome of the scan (FOCUSED or NOT_FOCUSED). This
+     * mode is optimized for focusing on objects very close to
+     * the camera.</p>
+     * <p>When that trigger is activated, AF will transition to
      * ACTIVE_SCAN, then to the outcome of the scan (FOCUSED or
-     * NOT_FOCUSED).  Triggering cancel AF resets the lens
+     * NOT_FOCUSED). Triggering cancel AF resets the lens
      * position to default, and sets the AF state to
      * INACTIVE.</p>
      * @see CaptureRequest#CONTROL_AF_MODE
@@ -830,8 +875,11 @@
     public static final int CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4;
 
     /**
-     * <p>Extended depth of field (digital focus). AF
-     * trigger is ignored, AF state should always be
+     * <p>Extended depth of field (digital focus) mode.</p>
+     * <p>The camera device will produce images with an extended
+     * depth of field automatically; no special focusing
+     * operations need to be done before taking a picture.</p>
+     * <p>AF triggers are ignored, and the AF state will always be
      * INACTIVE.</p>
      * @see CaptureRequest#CONTROL_AF_MODE
      */
@@ -865,8 +913,8 @@
     //
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
-     * the application-selected color transform matrix
+     * <p>The camera device's auto-white balance routine is disabled.</p>
+     * <p>The application-selected color transform matrix
      * ({@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}) and gains
      * ({@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}) are used by the camera
      * device for manual white balance control.</p>
@@ -878,9 +926,12 @@
     public static final int CONTROL_AWB_MODE_OFF = 0;
 
     /**
-     * <p>The camera device's auto white balance routine is active;
-     * the application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
-     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.</p>
+     * <p>The camera device's auto-white balance routine is active.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
@@ -889,65 +940,125 @@
     public static final int CONTROL_AWB_MODE_AUTO = 1;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses incandescent light as the assumed scene
-     * illumination for white balance. While the exact white balance
-     * transforms are up to the camera device, they will approximately
-     * match the CIE standard illuminant A.</p>
+     * illumination for white balance.</p>
+     * <p>While the exact white balance transforms are up to the
+     * camera device, they will approximately match the CIE
+     * standard illuminant A.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_INCANDESCENT = 2;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses fluorescent light as the assumed scene
-     * illumination for white balance. While the exact white balance
-     * transforms are up to the camera device, they will approximately
-     * match the CIE standard illuminant F2.</p>
+     * illumination for white balance.</p>
+     * <p>While the exact white balance transforms are up to the
+     * camera device, they will approximately match the CIE
+     * standard illuminant F2.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_FLUORESCENT = 3;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses warm fluorescent light as the assumed scene
-     * illumination for white balance. While the exact white balance
-     * transforms are up to the camera device, they will approximately
-     * match the CIE standard illuminant F4.</p>
+     * illumination for white balance.</p>
+     * <p>While the exact white balance transforms are up to the
+     * camera device, they will approximately match the CIE
+     * standard illuminant F4.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_WARM_FLUORESCENT = 4;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses daylight light as the assumed scene
-     * illumination for white balance. While the exact white balance
-     * transforms are up to the camera device, they will approximately
-     * match the CIE standard illuminant D65.</p>
+     * illumination for white balance.</p>
+     * <p>While the exact white balance transforms are up to the
+     * camera device, they will approximately match the CIE
+     * standard illuminant D65.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_DAYLIGHT = 5;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses cloudy daylight light as the assumed scene
      * illumination for white balance.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses twilight light as the assumed scene
      * illumination for white balance.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_TWILIGHT = 7;
 
     /**
-     * <p>The camera device's auto white balance routine is disabled;
+     * <p>The camera device's auto-white balance routine is disabled;
      * the camera device uses shade light as the assumed scene
      * illumination for white balance.</p>
+     * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+     * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+     * For devices that support the MANUAL_POST_PROCESSING capability, the
+     * values used by the camera device for the transform and gains
+     * will be available in the capture result for this request.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
      * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final int CONTROL_AWB_MODE_SHADE = 8;
@@ -957,38 +1068,43 @@
     //
 
     /**
-     * <p>This request doesn't fall into the other
-     * categories. Default to preview-like
+     * <p>The goal of this request doesn't fall into the other
+     * categories. The camera device will default to preview-like
      * behavior.</p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0;
 
     /**
-     * <p>This request is for a preview-like usecase. The
-     * precapture trigger may be used to start off a metering
-     * w/flash sequence</p>
+     * <p>This request is for a preview-like use case.</p>
+     * <p>The precapture trigger may be used to start off a metering
+     * w/flash sequence.</p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1;
 
     /**
      * <p>This request is for a still capture-type
-     * usecase.</p>
+     * use case.</p>
+     * <p>If the flash unit is under automatic control, it may fire as needed.</p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2;
 
     /**
      * <p>This request is for a video recording
-     * usecase.</p>
+     * use case.</p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3;
 
     /**
      * <p>This request is for a video snapshot (still
-     * image while recording video) usecase</p>
+     * image while recording video) use case.</p>
+     * <p>The camera device should take the highest-quality image
+     * possible (given the other settings) without disrupting the
+     * frame rate of video recording.<br />
+     * </p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
@@ -997,15 +1113,16 @@
      * <p>This request is for a ZSL usecase; the
      * application will stream full-resolution images and
      * reprocess one or several later for a final
-     * capture</p>
+     * capture.</p>
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      */
     public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5;
 
     /**
      * <p>This request is for manual capture use case where
-     * the applications want to directly control the capture parameters
-     * (e.g. {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} etc.).</p>
+     * the applications want to directly control the capture parameters.</p>
+     * <p>For example, the application may wish to manually control
+     * {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, etc.</p>
      *
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_SENSITIVITY
@@ -1025,7 +1142,8 @@
 
     /**
      * <p>A "monocolor" effect where the image is mapped into
-     * a single color.  This will typically be grayscale.</p>
+     * a single color.</p>
+     * <p>This will typically be grayscale.</p>
      * @see CaptureRequest#CONTROL_EFFECT_MODE
      */
     public static final int CONTROL_EFFECT_MODE_MONO = 1;
@@ -1085,31 +1203,42 @@
     //
 
     /**
-     * <p>Full application control of pipeline. All 3A
-     * routines are disabled, no other settings in
-     * android.control.* have any effect</p>
+     * <p>Full application control of pipeline.</p>
+     * <p>All control by the device's metering and focusing (3A)
+     * routines is disabled, and no other settings in
+     * android.control.* have any effect, except that
+     * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} may be used by the camera
+     * device to select post-processing values for processing
+     * blocks that do not allow for manual control, or are not
+     * exposed by the camera API.</p>
+     * <p>However, the camera device's 3A routines may continue to
+     * collect statistics and update their internal state so that
+     * when control is switched to AUTO mode, good control values
+     * can be immediately applied.</p>
+     *
+     * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      * @see CaptureRequest#CONTROL_MODE
      */
     public static final int CONTROL_MODE_OFF = 0;
 
     /**
-     * <p>Use settings for each individual 3A routine.
-     * Manual control of capture parameters is disabled. All
+     * <p>Use settings for each individual 3A routine.</p>
+     * <p>Manual control of capture parameters is disabled. All
      * controls in android.control.* besides sceneMode take
-     * effect</p>
+     * effect.</p>
      * @see CaptureRequest#CONTROL_MODE
      */
     public static final int CONTROL_MODE_AUTO = 1;
 
     /**
-     * <p>Use specific scene mode. Enabling this disables
-     * control.aeMode, control.awbMode and control.afMode
-     * controls; the camera device will ignore those settings while
-     * USE_SCENE_MODE is active (except for FACE_PRIORITY
-     * scene mode). Other control entries are still active.
-     * This setting can only be used if scene mode is supported
-     * (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes} contain some modes
-     * other than DISABLED).</p>
+     * <p>Use a specific scene mode.</p>
+     * <p>Enabling this disables control.aeMode, control.awbMode and
+     * control.afMode controls; the camera device will ignore
+     * those settings while USE_SCENE_MODE is active (except for
+     * FACE_PRIORITY scene mode). Other control entries are still
+     * active.  This setting can only be used if scene mode is
+     * supported (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}
+     * contain some modes other than DISABLED).</p>
      *
      * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
      * @see CaptureRequest#CONTROL_MODE
@@ -1119,7 +1248,12 @@
     /**
      * <p>Same as OFF mode, except that this capture will not be
      * used by camera device background auto-exposure, auto-white balance and
-     * auto-focus algorithms to update their statistics.</p>
+     * auto-focus algorithms (3A) to update their statistics.</p>
+     * <p>Specifically, the 3A routines are locked to the last
+     * values set from a request with AUTO, OFF, or
+     * USE_SCENE_MODE, and any statistics or state updates
+     * collected from manual captures with OFF_KEEP_STATE will be
+     * discarded by the camera device.</p>
      * @see CaptureRequest#CONTROL_MODE
      */
     public static final int CONTROL_MODE_OFF_KEEP_STATE = 3;
@@ -1137,8 +1271,9 @@
     /**
      * <p>If face detection support exists, use face
      * detection data for auto-focus, auto-white balance, and
-     * auto-exposure routines. If face detection statistics are
-     * disabled (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
+     * auto-exposure routines.</p>
+     * <p>If face detection statistics are disabled
+     * (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
      * this should still operate correctly (but will not return
      * face detection statistics to the framework).</p>
      * <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
@@ -1154,8 +1289,8 @@
     public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1;
 
     /**
-     * <p>Optimized for photos of quickly moving objects.
-     * Similar to SPORTS.</p>
+     * <p>Optimized for photos of quickly moving objects.</p>
+     * <p>Similar to SPORTS.</p>
      * @see CaptureRequest#CONTROL_SCENE_MODE
      */
     public static final int CONTROL_SCENE_MODE_ACTION = 2;
@@ -1224,8 +1359,8 @@
     public static final int CONTROL_SCENE_MODE_FIREWORKS = 12;
 
     /**
-     * <p>Optimized for photos of quickly moving people.
-     * Similar to ACTION.</p>
+     * <p>Optimized for photos of quickly moving people.</p>
+     * <p>Similar to ACTION.</p>
      * @see CaptureRequest#CONTROL_SCENE_MODE
      */
     public static final int CONTROL_SCENE_MODE_SPORTS = 13;
@@ -1257,11 +1392,13 @@
     //
 
     /**
+     * <p>Video stabilization is disabled.</p>
      * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
      */
     public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0;
 
     /**
+     * <p>Video stabilization is enabled.</p>
      * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
      */
     public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
@@ -1271,21 +1408,20 @@
     //
 
     /**
-     * <p>No edge enhancement is applied</p>
+     * <p>No edge enhancement is applied.</p>
      * @see CaptureRequest#EDGE_MODE
      */
     public static final int EDGE_MODE_OFF = 0;
 
     /**
-     * <p>Must not slow down frame rate relative to sensor
+     * <p>Apply edge enhancement at a quality level that does not slow down frame rate relative to sensor
      * output</p>
      * @see CaptureRequest#EDGE_MODE
      */
     public static final int EDGE_MODE_FAST = 1;
 
     /**
-     * <p>Frame rate may be reduced by high
-     * quality</p>
+     * <p>Apply high-quality edge enhancement, at a cost of reducing output frame rate.</p>
      * @see CaptureRequest#EDGE_MODE
      */
     public static final int EDGE_MODE_HIGH_QUALITY = 2;
@@ -1318,10 +1454,10 @@
     //
 
     /**
+     * <p>No hot pixel correction is applied.</p>
      * <p>The frame rate must not be reduced relative to sensor raw output
      * for this option.</p>
-     * <p>No hot pixel correction is applied.
-     * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+     * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
      *
      * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
      * @see CaptureRequest#HOT_PIXEL_MODE
@@ -1329,10 +1465,9 @@
     public static final int HOT_PIXEL_MODE_OFF = 0;
 
     /**
-     * <p>The frame rate must not be reduced relative to sensor raw output
-     * for this option.</p>
-     * <p>Hot pixel correction is applied.
-     * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+     * <p>Hot pixel correction is applied, without reducing frame
+     * rate relative to sensor raw output.</p>
+     * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
      *
      * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
      * @see CaptureRequest#HOT_PIXEL_MODE
@@ -1340,10 +1475,9 @@
     public static final int HOT_PIXEL_MODE_FAST = 1;
 
     /**
-     * <p>The frame rate may be reduced relative to sensor raw output
-     * for this option.</p>
-     * <p>A high-quality hot pixel correction is applied.
-     * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+     * <p>High-quality hot pixel correction is applied, at a cost
+     * of reducing frame rate relative to sensor raw output.</p>
+     * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
      *
      * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
      * @see CaptureRequest#HOT_PIXEL_MODE
@@ -1371,21 +1505,21 @@
     //
 
     /**
-     * <p>No noise reduction is applied</p>
+     * <p>No noise reduction is applied.</p>
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      */
     public static final int NOISE_REDUCTION_MODE_OFF = 0;
 
     /**
-     * <p>Must not slow down frame rate relative to sensor
-     * output</p>
+     * <p>Noise reduction is applied without reducing frame rate relative to sensor
+     * output.</p>
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      */
     public static final int NOISE_REDUCTION_MODE_FAST = 1;
 
     /**
-     * <p>May slow down frame rate to provide highest
-     * quality</p>
+     * <p>High-quality noise reduction is applied, at the cost of reducing frame rate
+     * relative to sensor output.</p>
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      */
     public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
@@ -1395,8 +1529,9 @@
     //
 
     /**
-     * <p>Default. No test pattern mode is used, and the camera
+     * <p>No test pattern mode is used, and the camera
      * device returns captures from the image sensor.</p>
+     * <p>This is the default if the key is not set.</p>
      * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
      */
     public static final int SENSOR_TEST_PATTERN_MODE_OFF = 0;
@@ -1500,19 +1635,21 @@
     //
 
     /**
-     * <p>No lens shading correction is applied</p>
+     * <p>No lens shading correction is applied.</p>
      * @see CaptureRequest#SHADING_MODE
      */
     public static final int SHADING_MODE_OFF = 0;
 
     /**
-     * <p>Must not slow down frame rate relative to sensor raw output</p>
+     * <p>Apply lens shading corrections, without slowing
+     * frame rate relative to sensor raw output</p>
      * @see CaptureRequest#SHADING_MODE
      */
     public static final int SHADING_MODE_FAST = 1;
 
     /**
-     * <p>Frame rate may be reduced by high quality</p>
+     * <p>Apply high-quality lens shading correction, at the
+     * cost of reduced frame rate.</p>
      * @see CaptureRequest#SHADING_MODE
      */
     public static final int SHADING_MODE_HIGH_QUALITY = 2;
@@ -1522,20 +1659,28 @@
     //
 
     /**
+     * <p>Do not include face detection statistics in capture
+     * results.</p>
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      */
     public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0;
 
     /**
-     * <p>Optional Return rectangle and confidence
-     * only</p>
+     * <p>Return face rectangle and confidence values only.</p>
+     * <p>In this mode, only android.statistics.faceRectangles and
+     * android.statistics.faceScores outputs are valid.</p>
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      */
     public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1;
 
     /**
-     * <p>Optional Return all face
-     * metadata</p>
+     * <p>Return all face
+     * metadata.</p>
+     * <p>In this mode,
+     * android.statistics.faceRectangles,
+     * android.statistics.faceScores,
+     * android.statistics.faceIds, and
+     * android.statistics.faceLandmarks outputs are valid.</p>
      * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      */
     public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
@@ -1545,11 +1690,13 @@
     //
 
     /**
+     * <p>Do not include a lens shading map in the capture result.</p>
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      */
     public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0;
 
     /**
+     * <p>Include a lens shading map in the capture result.</p>
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      */
     public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
@@ -1573,15 +1720,15 @@
     public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
 
     /**
-     * <p>Advanced gamma mapping and color enhancement may be applied.</p>
-     * <p>Should not slow down frame rate relative to raw sensor output.</p>
+     * <p>Advanced gamma mapping and color enhancement may be applied, without
+     * reducing frame rate compared to raw sensor output.</p>
      * @see CaptureRequest#TONEMAP_MODE
      */
     public static final int TONEMAP_MODE_FAST = 1;
 
     /**
-     * <p>Advanced gamma mapping and color enhancement may be applied.</p>
-     * <p>May slow down frame rate relative to raw sensor output.</p>
+     * <p>High-quality gamma mapping and color enhancement will be applied, at
+     * the cost of reduced frame rate compared to raw sensor output.</p>
      * @see CaptureRequest#TONEMAP_MODE
      */
     public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
@@ -1591,7 +1738,8 @@
     //
 
     /**
-     * <p>AE is off or recently reset. When a camera device is opened, it starts in
+     * <p>AE is off or recently reset.</p>
+     * <p>When a camera device is opened, it starts in
      * this state. This is a transient state, the camera device may skip reporting
      * this state in capture result.</p>
      * @see CaptureResult#CONTROL_AE_STATE
@@ -1600,7 +1748,8 @@
 
     /**
      * <p>AE doesn't yet have a good set of control values
-     * for the current scene. This is a transient state, the camera device may skip
+     * for the current scene.</p>
+     * <p>This is a transient state, the camera device may skip
      * reporting this state in capture result.</p>
      * @see CaptureResult#CONTROL_AE_STATE
      */
@@ -1629,11 +1778,13 @@
 
     /**
      * <p>AE has been asked to do a precapture sequence
-     * (through the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} START),
-     * and is currently executing it. Once PRECAPTURE
-     * completes, AE will transition to CONVERGED or
-     * FLASH_REQUIRED as appropriate. This is a transient state, the
-     * camera device may skip reporting this state in capture result.</p>
+     * and is currently executing it.</p>
+     * <p>Precapture can be triggered through setting
+     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START.</p>
+     * <p>Once PRECAPTURE completes, AE will transition to CONVERGED
+     * or FLASH_REQUIRED as appropriate. This is a transient
+     * state, the camera device may skip reporting this state in
+     * capture result.</p>
      *
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      * @see CaptureResult#CONTROL_AE_STATE
@@ -1645,61 +1796,78 @@
     //
 
     /**
-     * <p>AF off or has not yet tried to scan/been asked
-     * to scan.  When a camera device is opened, it starts in
-     * this state. This is a transient state, the camera device may
-     * skip reporting this state in capture result.</p>
+     * <p>AF is off or has not yet tried to scan/been asked
+     * to scan.</p>
+     * <p>When a camera device is opened, it starts in this
+     * state. This is a transient state, the camera device may
+     * skip reporting this state in capture
+     * result.</p>
      * @see CaptureResult#CONTROL_AF_STATE
      */
     public static final int CONTROL_AF_STATE_INACTIVE = 0;
 
     /**
-     * <p>if CONTINUOUS_* modes are supported. AF is
-     * currently doing an AF scan initiated by a continuous
-     * autofocus mode. This is a transient state, the camera device may
-     * skip reporting this state in capture result.</p>
+     * <p>AF is currently performing an AF scan initiated the
+     * camera device in a continuous autofocus mode.</p>
+     * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+     * state, the camera device may skip reporting this state in
+     * capture result.</p>
      * @see CaptureResult#CONTROL_AF_STATE
      */
     public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1;
 
     /**
-     * <p>if CONTINUOUS_* modes are supported. AF currently
-     * believes it is in focus, but may restart scanning at
-     * any time. This is a transient state, the camera device may skip
-     * reporting this state in capture result.</p>
+     * <p>AF currently believes it is in focus, but may
+     * restart scanning at any time.</p>
+     * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+     * state, the camera device may skip reporting this state in
+     * capture result.</p>
      * @see CaptureResult#CONTROL_AF_STATE
      */
     public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2;
 
     /**
-     * <p>if AUTO or MACRO modes are supported. AF is doing
-     * an AF scan because it was triggered by AF trigger. This is a
-     * transient state, the camera device may skip reporting
-     * this state in capture result.</p>
+     * <p>AF is performing an AF scan because it was
+     * triggered by AF trigger.</p>
+     * <p>Only used by AUTO or MACRO AF modes. This is a transient
+     * state, the camera device may skip reporting this state in
+     * capture result.</p>
      * @see CaptureResult#CONTROL_AF_STATE
      */
     public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3;
 
     /**
-     * <p>if any AF mode besides OFF is supported. AF
-     * believes it is focused correctly and is
-     * locked.</p>
+     * <p>AF believes it is focused correctly and has locked
+     * focus.</p>
+     * <p>This state is reached only after an explicit START AF trigger has been
+     * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus has been obtained.</p>
+     * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+     * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+     *
+     * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
      * @see CaptureResult#CONTROL_AF_STATE
      */
     public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4;
 
     /**
-     * <p>if any AF mode besides OFF is supported. AF has
-     * failed to focus successfully and is
-     * locked.</p>
+     * <p>AF has failed to focus successfully and has locked
+     * focus.</p>
+     * <p>This state is reached only after an explicit START AF trigger has been
+     * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus cannot be obtained.</p>
+     * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+     * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+     *
+     * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
      * @see CaptureResult#CONTROL_AF_STATE
      */
     public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5;
 
     /**
-     * <p>if CONTINUOUS_* modes are supported. AF finished a
-     * passive scan without finding focus, and may restart
-     * scanning at any time. This is a transient state, the camera
+     * <p>AF finished a passive scan without finding focus,
+     * and may restart scanning at any time.</p>
+     * <p>Only used by CONTINUOUS_* AF modes. This is a transient state, the camera
      * device may skip reporting this state in capture result.</p>
      * @see CaptureResult#CONTROL_AF_STATE
      */
@@ -1710,16 +1878,19 @@
     //
 
     /**
-     * <p>AWB is not in auto mode.  When a camera device is opened, it
-     * starts in this state. This is a transient state, the camera device may
-     * skip reporting this state in capture result.</p>
+     * <p>AWB is not in auto mode, or has not yet started metering.</p>
+     * <p>When a camera device is opened, it starts in this
+     * state. This is a transient state, the camera device may
+     * skip reporting this state in capture
+     * result.</p>
      * @see CaptureResult#CONTROL_AWB_STATE
      */
     public static final int CONTROL_AWB_STATE_INACTIVE = 0;
 
     /**
      * <p>AWB doesn't yet have a good set of control
-     * values for the current scene. This is a transient state, the camera device
+     * values for the current scene.</p>
+     * <p>This is a transient state, the camera device
      * may skip reporting this state in capture result.</p>
      * @see CaptureResult#CONTROL_AWB_STATE
      */
@@ -1767,8 +1938,9 @@
     public static final int FLASH_STATE_FIRED = 3;
 
     /**
-     * <p>Flash partially illuminated this frame. This is usually due to the next
-     * or previous frame having the flash fire, and the flash spilling into this capture
+     * <p>Flash partially illuminated this frame.</p>
+     * <p>This is usually due to the next or previous frame having
+     * the flash fire, and the flash spilling into this capture
      * due to hardware limitations.</p>
      * @see CaptureResult#FLASH_STATE
      */
@@ -1791,8 +1963,10 @@
     public static final int LENS_STATE_STATIONARY = 0;
 
     /**
-     * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
-     * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+     * <p>One or several of the lens parameters
+     * ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+     * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is
+     * currently changing.</p>
      *
      * @see CaptureRequest#LENS_APERTURE
      * @see CaptureRequest#LENS_FILTER_DENSITY
@@ -1807,16 +1981,22 @@
     //
 
     /**
+     * <p>The camera device does not detect any flickering illumination
+     * in the current scene.</p>
      * @see CaptureResult#STATISTICS_SCENE_FLICKER
      */
     public static final int STATISTICS_SCENE_FLICKER_NONE = 0;
 
     /**
+     * <p>The camera device detects illumination flickering at 50Hz
+     * in the current scene.</p>
      * @see CaptureResult#STATISTICS_SCENE_FLICKER
      */
     public static final int STATISTICS_SCENE_FLICKER_50HZ = 1;
 
     /**
+     * <p>The camera device detects illumination flickering at 60Hz
+     * in the current scene.</p>
      * @see CaptureResult#STATISTICS_SCENE_FLICKER
      */
     public static final int STATISTICS_SCENE_FLICKER_60HZ = 2;
@@ -1826,8 +2006,8 @@
     //
 
     /**
-     * <p>The current result is not yet fully synchronized to any request.
-     * Synchronization is in progress, and reading metadata from this
+     * <p>The current result is not yet fully synchronized to any request.</p>
+     * <p>Synchronization is in progress, and reading metadata from this
      * result may include a mix of data that have taken effect since the
      * last synchronization time.</p>
      * <p>In some future result, within {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} frames,
@@ -1842,10 +2022,10 @@
     public static final int SYNC_FRAME_NUMBER_CONVERGING = -1;
 
     /**
-     * <p>The current result's synchronization status is unknown. The
-     * result may have already converged, or it may be in progress.
-     * Reading from this result may include some mix of settings from
-     * past requests.</p>
+     * <p>The current result's synchronization status is unknown.</p>
+     * <p>The result may have already converged, or it may be in
+     * progress.  Reading from this result may include some mix
+     * of settings from past requests.</p>
      * <p>After a settings change, the new settings will eventually all
      * take effect for the output buffers and results. However, this
      * value will not change when that happens. Altering settings
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index d4dfdd5..2cfb611 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -43,14 +43,14 @@
  * <p>CaptureRequests can be created by using a {@link Builder} instance,
  * obtained by calling {@link CameraDevice#createCaptureRequest}</p>
  *
- * <p>CaptureRequests are given to {@link CameraDevice#capture} or
- * {@link CameraDevice#setRepeatingRequest} to capture images from a camera.</p>
+ * <p>CaptureRequests are given to {@link CameraCaptureSession#capture} or
+ * {@link CameraCaptureSession#setRepeatingRequest} to capture images from a camera.</p>
  *
  * <p>Each request can specify a different subset of target Surfaces for the
  * camera to send the captured data to. All the surfaces used in a request must
  * be part of the surface list given to the last call to
- * {@link CameraDevice#configureOutputs}, when the request is submitted to the
- * camera device.</p>
+ * {@link CameraDevice#createCaptureSession}, when the request is submitted to the
+ * session.</p>
  *
  * <p>For example, a request meant for repeating preview might only include the
  * Surface for the preview SurfaceView or SurfaceTexture, while a
@@ -357,11 +357,11 @@
      * request fields to one of the templates defined in {@link CameraDevice}.
      *
      * @see CameraDevice#createCaptureRequest
-     * @see #TEMPLATE_PREVIEW
-     * @see #TEMPLATE_RECORD
-     * @see #TEMPLATE_STILL_CAPTURE
-     * @see #TEMPLATE_VIDEO_SNAPSHOT
-     * @see #TEMPLATE_MANUAL
+     * @see CameraDevice#TEMPLATE_PREVIEW
+     * @see CameraDevice#TEMPLATE_RECORD
+     * @see CameraDevice#TEMPLATE_STILL_CAPTURE
+     * @see CameraDevice#TEMPLATE_VIDEO_SNAPSHOT
+     * @see CameraDevice#TEMPLATE_MANUAL
      */
     public final static class Builder {
 
@@ -381,7 +381,7 @@
          * <p>Add a surface to the list of targets for this request</p>
          *
          * <p>The Surface added must be one of the surfaces included in the most
-         * recent call to {@link CameraDevice#configureOutputs}, when the
+         * recent call to {@link CameraDevice#createCaptureSession}, when the
          * request is given to the camera device.</p>
          *
          * <p>Adding a target more than once has no effect.</p>
@@ -473,7 +473,7 @@
     /**
      * <p>The mode control selects how the image data is converted from the
      * sensor's native color into linear sRGB color.</p>
-     * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+     * <p>When auto-white balance (AWB) is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
      * control is overridden by the AWB routine. When AWB is disabled, the
      * application controls how the color mapping is performed.</p>
      * <p>We define the expected processing pipeline below. For consistency
@@ -524,7 +524,7 @@
 
     /**
      * <p>A color transform matrix to use to transform
-     * from sensor RGB color space to output linear sRGB color space</p>
+     * from sensor RGB color space to output linear sRGB color space.</p>
      * <p>This matrix is either set by the camera device when the request
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
      * directly by the application in the request when the
@@ -600,13 +600,17 @@
             new Key<Integer>("android.control.aeAntibandingMode", int.class);
 
     /**
-     * <p>Adjustment to AE target image
-     * 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 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>Adjustment to auto-exposure (AE) target image
+     * brightness.</p>
+     * <p>The adjustment is measured as a count of steps, with the
+     * step size defined by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} and the
+     * allowed range by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE android.control.aeCompensationRange}.</p>
+     * <p>For example, if the exposure value (EV) step is 0.333, '6'
+     * will mean an exposure compensation of +2 EV; -3 will mean an
+     * exposure compensation of -1 EV. One EV represents a doubling
+     * of image brightness. 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
@@ -614,6 +618,8 @@
      * 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 CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE
+     * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
      * @see CaptureRequest#CONTROL_AE_LOCK
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureResult#CONTROL_AE_STATE
@@ -622,7 +628,7 @@
             new Key<Integer>("android.control.aeExposureCompensation", int.class);
 
     /**
-     * <p>Whether AE is currently locked to its latest
+     * <p>Whether auto-exposure (AE) is currently locked to its latest
      * calculated values.</p>
      * <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 /
@@ -711,9 +717,9 @@
 
     /**
      * <p>Range over which fps can be adjusted to
-     * maintain exposure</p>
-     * <p>Only constrains AE algorithm, not manual control
-     * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+     * maintain exposure.</p>
+     * <p>Only constrains auto-exposure (AE) algorithm, not
+     * manual control of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
      *
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      */
@@ -727,9 +733,18 @@
      * included at all in the request settings. When included and
      * set to START, the camera device will trigger the autoexposure
      * precapture metering sequence.</p>
-     * <p>The effect of AE precapture trigger depends on the current
-     * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
-     * state transition details.</p>
+     * <p>The precapture sequence should triggered before starting a
+     * high-quality still capture for final metering decisions to
+     * be made, and for firing pre-capture flash pulses to estimate
+     * scene brightness and required final capture flash power, when
+     * the flash is enabled.</p>
+     * <p>Normally, this entry should be set to START for only a
+     * single request, and the application should wait until the
+     * sequence completes before starting a new one.</p>
+     * <p>The exact effect of auto-exposure (AE) precapture trigger
+     * depends on the current AE mode and state; see
+     * {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
+     * details.</p>
      *
      * @see CaptureResult#CONTROL_AE_STATE
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
@@ -739,8 +754,8 @@
             new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
 
     /**
-     * <p>Whether AF is currently enabled, and what
-     * mode it is set to</p>
+     * <p>Whether auto-focus (AF) is currently enabled, and what
+     * mode it is set to.</p>
      * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
      * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} &gt; 0</code>).</p>
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
@@ -793,7 +808,11 @@
      * autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
      * <p>When set to CANCEL, the camera device will cancel any active trigger,
      * and return to its initial AF state.</p>
-     * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+     * <p>Generally, applications should set this entry to START or CANCEL for only a
+     * single capture, and then return it to IDLE (or not set at all). Specifying
+     * START for multiple captures in a row means restarting the AF operation over
+     * and over again.</p>
+     * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
      *
      * @see CaptureResult#CONTROL_AF_STATE
      * @see #CONTROL_AF_TRIGGER_IDLE
@@ -804,31 +823,37 @@
             new Key<Integer>("android.control.afTrigger", int.class);
 
     /**
-     * <p>Whether AWB is currently locked to its
+     * <p>Whether auto-white balance (AWB) is currently locked to its
      * latest calculated values.</p>
-     * <p>Note that AWB lock is only meaningful for AUTO
-     * mode; in other modes, AWB is already fixed to a specific
-     * setting.</p>
+     * <p>Note that AWB lock is only meaningful when
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+     * AWB is already fixed to a specific setting.</p>
+     *
+     * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final Key<Boolean> CONTROL_AWB_LOCK =
             new Key<Boolean>("android.control.awbLock", boolean.class);
 
     /**
-     * <p>Whether AWB is currently setting the color
+     * <p>Whether auto-white balance (AWB) is currently setting the color
      * transform fields, and what its illumination target
      * is.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
-     * <p>When set to the ON mode, the camera device's auto white balance
+     * <p>When set to the ON mode, the camera device's auto-white balance
      * routine is enabled, overriding the application's selected
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
-     * <p>When set to the OFF mode, the camera device's auto white balance
+     * <p>When set to the OFF mode, the camera device's auto-white balance
      * routine is disabled. The application manually controls the white
      * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
      * and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
-     * <p>When set to any other modes, the camera device's auto white balance
-     * routine is disabled. The camera device uses each particular illumination
-     * target for white balance adjustment.</p>
+     * <p>When set to any other modes, the camera device's auto-white
+     * balance routine is disabled. The camera device uses each
+     * particular illumination target for white balance
+     * adjustment. The application's values for
+     * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+     * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -879,8 +904,8 @@
      * strategy.</p>
      * <p>This control (except for MANUAL) is only effective if
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
-     * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * contains MANUAL_SENSOR.</p>
      *
      * @see CaptureRequest#CONTROL_MODE
@@ -955,7 +980,9 @@
      * <p>This is the mode that that is active when
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
      * these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
-     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+     * The scene modes available for a given camera device are listed in
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</p>
      * <p>The interpretation and implementation of these scene modes is left
      * to the implementor of the camera device. Their behavior will not be
      * consistent across all devices, and any given device may only implement
@@ -963,6 +990,7 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CaptureRequest#CONTROL_MODE
      * @see #CONTROL_SCENE_MODE_DISABLED
@@ -988,11 +1016,21 @@
 
     /**
      * <p>Whether video stabilization is
-     * active</p>
+     * active.</p>
+     * <p>Video stabilization automatically translates and scales images from the camera
+     * in order to stabilize motion between consecutive frames.</p>
      * <p>If enabled, video stabilization can modify the
-     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
-     * stabilized</p>
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
+     * <p>Switching between different video stabilization modes may take several frames
+     * to initialize, the camera device will report the current mode in capture result
+     * metadata. For example, When "ON" mode is requested, the video stabilization modes
+     * in the first several capture results may still be "OFF", and it will become "ON"
+     * when the initialization is done.</p>
+     * <p>If a camera device supports both this mode and OIS ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}),
+     * turning both modes on may produce undesirable interaction, so it is recommended not to
+     * enable both at the same time.</p>
      *
+     * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
      * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
@@ -1030,7 +1068,7 @@
      * <p>When set to OFF, the camera device will not fire flash for this capture.</p>
      * <p>When set to SINGLE, the camera device will fire flash regardless of the camera
      * device's auto-exposure routine's result. When used in still capture case, this
-     * control should be used along with AE precapture metering sequence
+     * control should be used along with auto-exposure (AE) precapture metering sequence
      * ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
      * <p>When set to TORCH, the flash will be on continuously. This mode can be used
      * for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
@@ -1102,21 +1140,21 @@
 
     /**
      * <p>Compression quality of the final JPEG
-     * image</p>
-     * <p>85-95 is typical usage range</p>
+     * image.</p>
+     * <p>85-95 is typical usage range.</p>
      */
     public static final Key<Byte> JPEG_QUALITY =
             new Key<Byte>("android.jpeg.quality", byte.class);
 
     /**
      * <p>Compression quality of JPEG
-     * thumbnail</p>
+     * thumbnail.</p>
      */
     public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
             new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
 
     /**
-     * <p>Resolution of embedded JPEG thumbnail</p>
+     * <p>Resolution of embedded JPEG thumbnail.</p>
      * <p>When set to (0, 0) value, the JPEG EXIF will not contain thumbnail,
      * but the captured JPEG will still be a valid image.</p>
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
@@ -1204,7 +1242,7 @@
 
     /**
      * <p>Distance to plane of sharpest focus,
-     * measured from frontmost surface of the lens</p>
+     * measured from frontmost surface of the lens.</p>
      * <p>0 means infinity focus. Used value will be clamped
      * to [0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}].</p>
      * <p>Like {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, this setting won't be applied
@@ -1222,12 +1260,26 @@
     /**
      * <p>Sets whether the camera device uses optical image stabilization (OIS)
      * when capturing images.</p>
-     * <p>OIS is used to compensate for motion blur due to small movements of
-     * the camera during capture. Unlike digital image stabilization, OIS makes
-     * use of mechanical elements to stabilize the camera sensor, and thus
-     * allows for longer exposure times before camera shake becomes
-     * apparent.</p>
-     * <p>This is not expected to be supported on most devices.</p>
+     * <p>OIS is used to compensate for motion blur due to small
+     * movements of the camera during capture. Unlike digital image
+     * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+     * makes use of mechanical elements to stabilize the camera
+     * sensor, and thus allows for longer exposure times before
+     * camera shake becomes apparent.</p>
+     * <p>Switching between different optical stabilization modes may take several
+     * frames to initialize, the camera device will report the current mode in
+     * capture result metadata. For example, When "ON" mode is requested, the
+     * optical stabilization modes in the first several capture results may still
+     * be "OFF", and it will become "ON" when the initialization is done.</p>
+     * <p>If a camera device supports both OIS and EIS ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}),
+     * turning both modes on may produce undesirable interaction, so it is recommended not
+     * to enable both at the same time.</p>
+     * <p>Not all devices will support OIS; see
+     * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+     * available controls.</p>
+     *
+     * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+     * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
      * @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
      * @see #LENS_OPTICAL_STABILIZATION_MODE_ON
      */
@@ -1235,16 +1287,15 @@
             new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
 
     /**
-     * <p>Mode of operation for the noise reduction
-     * algorithm</p>
+     * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>Noise filtering control. OFF means no noise reduction
      * will be applied by the camera device.</p>
-     * <p>This must be set to a valid mode in
+     * <p>This must be set to a valid mode from
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
      * <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
      * will be applied. HIGH_QUALITY mode indicates that the camera device
      * will use the highest-quality noise filtering algorithms,
-     * even if it slows down capture rate. FAST means the camera device should not
+     * even if it slows down capture rate. FAST means the camera device will not
      * slow down capture rate when applying noise filtering.</p>
      *
      * @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -1265,40 +1316,39 @@
             new Key<Integer>("android.request.id", int.class);
 
     /**
-     * <p>(x, y, width, height).</p>
-     * <p>A rectangle with the top-level corner of (x,y) and size
-     * (width, height). The region of the sensor that is used for
-     * output. Each stream must use this rectangle to produce its
-     * output, cropping to a smaller region if necessary to
-     * maintain the stream's aspect ratio.</p>
-     * <p>HAL2.x uses only (x, y, width)</p>
-     * <p>The crop region is applied after the RAW to other color space (e.g. YUV)
-     * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage,
-     * it is not croppable. The crop region will be ignored by raw streams.</p>
+     * <p>The region of the sensor to read out for this capture.</p>
+     * <p>The crop region coordinate system is based off
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
+     * top-left corner of the sensor active array.</p>
+     * <p>Output streams use this rectangle to produce their output,
+     * cropping to a smaller region if necessary to maintain the
+     * stream's aspect ratio, then scaling the sensor input to
+     * match the output's configured resolution.</p>
+     * <p>The crop region is applied after the RAW to other color
+     * space (e.g. YUV) conversion. Since raw streams
+     * (e.g. RAW16) don't have the conversion stage, they are not
+     * croppable. The crop region will be ignored by raw streams.</p>
      * <p>For non-raw streams, any additional per-stream cropping will
      * be done to maximize the final pixel area of the stream.</p>
      * <p>For example, if the crop region is set to a 4:3 aspect
-     * ratio, then 4:3 streams should use the exact crop
-     * region. 16:9 streams should further crop vertically
+     * ratio, then 4:3 streams will use the exact crop
+     * region. 16:9 streams will further crop vertically
      * (letterbox).</p>
      * <p>Conversely, if the crop region is set to a 16:9, then 4:3
-     * outputs should crop horizontally (pillarbox), and 16:9
-     * streams should match exactly. These additional crops must
+     * outputs will crop horizontally (pillarbox), and 16:9
+     * streams will match exactly. These additional crops will
      * be centered within the crop region.</p>
-     * <p>The output streams must maintain square pixels at all
-     * times, no matter what the relative aspect ratios of the
-     * crop region and the stream are.  Negative values for
-     * corner are allowed for raw output if full pixel array is
-     * larger than active pixel array. Width and height may be
-     * rounded to nearest larger supportable width, especially
-     * for raw output, where only a few fixed scales may be
-     * possible. The width and height of the crop region cannot
-     * be set to be smaller than floor( activeArraySize.width /
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} ) and floor(
-     * activeArraySize.height /
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom}), respectively.</p>
+     * <p>The width and height of the crop region cannot
+     * be set to be smaller than
+     * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
+     * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+     * <p>The camera device may adjust the crop region to account
+     * for rounding and other hardware requirements; the final
+     * crop region used will be included in the output capture
+     * result.</p>
      *
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
     public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
             new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
@@ -1391,12 +1441,20 @@
             new Key<Long>("android.sensor.frameDuration", long.class);
 
     /**
-     * <p>Gain applied to image data. Must be
-     * implemented through analog gain only if set to values
-     * below 'maximum analog sensitivity'.</p>
-     * <p>If the sensor can't apply this exact gain, it should lessen the
-     * gain to the nearest possible value (rather than gain more).</p>
-     * <p>ISO 12232:2006 REI method</p>
+     * <p>The amount of gain applied to sensor data
+     * before processing.</p>
+     * <p>The sensitivity is the standard ISO sensitivity value,
+     * as defined in ISO 12232:2006.</p>
+     * <p>The sensitivity must be within {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}, and
+     * if if it less than {@link CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY android.sensor.maxAnalogSensitivity}, the camera device
+     * is guaranteed to use only analog amplification for applying the gain.</p>
+     * <p>If the camera device cannot apply the exact sensitivity
+     * requested, it will reduce the gain to the nearest supported
+     * value. The final sensitivity used will be available in the
+     * output capture result.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+     * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
      */
     public static final Key<Integer> SENSOR_SENSITIVITY =
             new Key<Integer>("android.sensor.sensitivity", int.class);
@@ -1421,7 +1479,7 @@
      * <p>When enabled, the sensor sends a test pattern instead of
      * doing a real exposure from the camera.</p>
      * <p>When a test pattern is enabled, all manual sensor controls specified
-     * by android.sensor.* should be ignored. All other controls should
+     * by android.sensor.* will be ignored. All other controls should
      * work as normal.</p>
      * <p>For example, if manual flash is enabled, flash firing should still
      * occur (and that the test pattern remain unmodified, since the flash
@@ -1459,7 +1517,7 @@
      * lens shading map data in android.statistics.lensShadingMap, with size specified
      * by android.lens.info.shadingMapSize; the returned shading map data will be the one
      * applied by the camera device for this capture request.</p>
-     * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability
+     * <p>The shading map data may depend on the auto-exposure (AE) and AWB statistics, therefore the reliability
      * of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in
      * AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code> OFF),
      * to get best results, it is recommended that the applications wait for the AE and AWB to
@@ -1476,8 +1534,8 @@
             new Key<Integer>("android.shading.mode", int.class);
 
     /**
-     * <p>State of the face detector
-     * unit</p>
+     * <p>Control for the face detector
+     * unit.</p>
      * <p>Whether face detection is enabled, and whether it
      * should output just the basic fields or the full set of
      * fields. Value must be one of the
@@ -1494,7 +1552,7 @@
     /**
      * <p>Operating mode for hotpixel map generation.</p>
      * <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
-     * If set to OFF, no hotpixel map should be returned.</p>
+     * If set to OFF, no hotpixel map will be returned.</p>
      * <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
      *
      * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -1507,7 +1565,7 @@
      * <p>Whether the camera device will output the lens
      * shading map in output result metadata.</p>
      * <p>When set to ON,
-     * android.statistics.lensShadingMap must be provided in
+     * android.statistics.lensShadingMap will be provided in
      * the output result metadata.</p>
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 7d07c92..9097220 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -319,7 +319,7 @@
     /**
      * <p>The mode control selects how the image data is converted from the
      * sensor's native color into linear sRGB color.</p>
-     * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+     * <p>When auto-white balance (AWB) is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
      * control is overridden by the AWB routine. When AWB is disabled, the
      * application controls how the color mapping is performed.</p>
      * <p>We define the expected processing pipeline below. For consistency
@@ -370,7 +370,7 @@
 
     /**
      * <p>A color transform matrix to use to transform
-     * from sensor RGB color space to output linear sRGB color space</p>
+     * from sensor RGB color space to output linear sRGB color space.</p>
      * <p>This matrix is either set by the camera device when the request
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
      * directly by the application in the request when the
@@ -446,13 +446,17 @@
             new Key<Integer>("android.control.aeAntibandingMode", int.class);
 
     /**
-     * <p>Adjustment to AE target image
-     * 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 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>Adjustment to auto-exposure (AE) target image
+     * brightness.</p>
+     * <p>The adjustment is measured as a count of steps, with the
+     * step size defined by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} and the
+     * allowed range by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE android.control.aeCompensationRange}.</p>
+     * <p>For example, if the exposure value (EV) step is 0.333, '6'
+     * will mean an exposure compensation of +2 EV; -3 will mean an
+     * exposure compensation of -1 EV. One EV represents a doubling
+     * of image brightness. 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
@@ -460,6 +464,8 @@
      * 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 CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE
+     * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
      * @see CaptureRequest#CONTROL_AE_LOCK
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureResult#CONTROL_AE_STATE
@@ -468,7 +474,7 @@
             new Key<Integer>("android.control.aeExposureCompensation", int.class);
 
     /**
-     * <p>Whether AE is currently locked to its latest
+     * <p>Whether auto-exposure (AE) is currently locked to its latest
      * calculated values.</p>
      * <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 /
@@ -557,9 +563,9 @@
 
     /**
      * <p>Range over which fps can be adjusted to
-     * maintain exposure</p>
-     * <p>Only constrains AE algorithm, not manual control
-     * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+     * maintain exposure.</p>
+     * <p>Only constrains auto-exposure (AE) algorithm, not
+     * manual control of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
      *
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      */
@@ -573,9 +579,18 @@
      * included at all in the request settings. When included and
      * set to START, the camera device will trigger the autoexposure
      * precapture metering sequence.</p>
-     * <p>The effect of AE precapture trigger depends on the current
-     * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
-     * state transition details.</p>
+     * <p>The precapture sequence should triggered before starting a
+     * high-quality still capture for final metering decisions to
+     * be made, and for firing pre-capture flash pulses to estimate
+     * scene brightness and required final capture flash power, when
+     * the flash is enabled.</p>
+     * <p>Normally, this entry should be set to START for only a
+     * single request, and the application should wait until the
+     * sequence completes before starting a new one.</p>
+     * <p>The exact effect of auto-exposure (AE) precapture trigger
+     * depends on the current AE mode and state; see
+     * {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
+     * details.</p>
      *
      * @see CaptureResult#CONTROL_AE_STATE
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
@@ -585,7 +600,7 @@
             new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
 
     /**
-     * <p>Current state of AE algorithm</p>
+     * <p>Current state of the auto-exposure (AE) algorithm.</p>
      * <p>Switching between or enabling AE modes ({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}) always
      * resets the AE state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
      * or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -783,8 +798,8 @@
             new Key<Integer>("android.control.aeState", int.class);
 
     /**
-     * <p>Whether AF is currently enabled, and what
-     * mode it is set to</p>
+     * <p>Whether auto-focus (AF) is currently enabled, and what
+     * mode it is set to.</p>
      * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
      * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} &gt; 0</code>).</p>
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
@@ -837,7 +852,11 @@
      * autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
      * <p>When set to CANCEL, the camera device will cancel any active trigger,
      * and return to its initial AF state.</p>
-     * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+     * <p>Generally, applications should set this entry to START or CANCEL for only a
+     * single capture, and then return it to IDLE (or not set at all). Specifying
+     * START for multiple captures in a row means restarting the AF operation over
+     * and over again.</p>
+     * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
      *
      * @see CaptureResult#CONTROL_AF_STATE
      * @see #CONTROL_AF_TRIGGER_IDLE
@@ -848,7 +867,7 @@
             new Key<Integer>("android.control.afTrigger", int.class);
 
     /**
-     * <p>Current state of AF algorithm.</p>
+     * <p>Current state of auto-focus (AF) algorithm.</p>
      * <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always
      * resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
      * or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -1027,13 +1046,13 @@
      * <td align="center">PASSIVE_SCAN</td>
      * <td align="center">AF_TRIGGER</td>
      * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Immediate trans. If focus is good, Lens now locked</td>
+     * <td align="center">Immediate transition, if focus is good. Lens now locked</td>
      * </tr>
      * <tr>
      * <td align="center">PASSIVE_SCAN</td>
      * <td align="center">AF_TRIGGER</td>
      * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Immediate trans. if focus is bad, Lens now locked</td>
+     * <td align="center">Immediate transition, if focus is bad. Lens now locked</td>
      * </tr>
      * <tr>
      * <td align="center">PASSIVE_SCAN</td>
@@ -1057,13 +1076,13 @@
      * <td align="center">PASSIVE_FOCUSED</td>
      * <td align="center">AF_TRIGGER</td>
      * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Immediate trans. Lens now locked</td>
+     * <td align="center">Immediate transition, lens now locked</td>
      * </tr>
      * <tr>
      * <td align="center">PASSIVE_UNFOCUSED</td>
      * <td align="center">AF_TRIGGER</td>
      * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Immediate trans. Lens now locked</td>
+     * <td align="center">Immediate transition, lens now locked</td>
      * </tr>
      * <tr>
      * <td align="center">FOCUSED_LOCKED</td>
@@ -1130,13 +1149,13 @@
      * <td align="center">PASSIVE_SCAN</td>
      * <td align="center">AF_TRIGGER</td>
      * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Eventual trans. once focus good, Lens now locked</td>
+     * <td align="center">Eventual transition once the focus is good. Lens now locked</td>
      * </tr>
      * <tr>
      * <td align="center">PASSIVE_SCAN</td>
      * <td align="center">AF_TRIGGER</td>
      * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Eventual trans. if cannot focus, Lens now locked</td>
+     * <td align="center">Eventual transition if cannot find focus. Lens now locked</td>
      * </tr>
      * <tr>
      * <td align="center">PASSIVE_SCAN</td>
@@ -1245,31 +1264,37 @@
             new Key<Integer>("android.control.afState", int.class);
 
     /**
-     * <p>Whether AWB is currently locked to its
+     * <p>Whether auto-white balance (AWB) is currently locked to its
      * latest calculated values.</p>
-     * <p>Note that AWB lock is only meaningful for AUTO
-     * mode; in other modes, AWB is already fixed to a specific
-     * setting.</p>
+     * <p>Note that AWB lock is only meaningful when
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+     * AWB is already fixed to a specific setting.</p>
+     *
+     * @see CaptureRequest#CONTROL_AWB_MODE
      */
     public static final Key<Boolean> CONTROL_AWB_LOCK =
             new Key<Boolean>("android.control.awbLock", boolean.class);
 
     /**
-     * <p>Whether AWB is currently setting the color
+     * <p>Whether auto-white balance (AWB) is currently setting the color
      * transform fields, and what its illumination target
      * is.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
-     * <p>When set to the ON mode, the camera device's auto white balance
+     * <p>When set to the ON mode, the camera device's auto-white balance
      * routine is enabled, overriding the application's selected
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
-     * <p>When set to the OFF mode, the camera device's auto white balance
+     * <p>When set to the OFF mode, the camera device's auto-white balance
      * routine is disabled. The application manually controls the white
      * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
      * and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
-     * <p>When set to any other modes, the camera device's auto white balance
-     * routine is disabled. The camera device uses each particular illumination
-     * target for white balance adjustment.</p>
+     * <p>When set to any other modes, the camera device's auto-white
+     * balance routine is disabled. The camera device uses each
+     * particular illumination target for white balance
+     * adjustment. The application's values for
+     * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+     * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -1320,8 +1345,8 @@
      * strategy.</p>
      * <p>This control (except for MANUAL) is only effective if
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
-     * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * contains MANUAL_SENSOR.</p>
      *
      * @see CaptureRequest#CONTROL_MODE
@@ -1338,7 +1363,7 @@
             new Key<Integer>("android.control.captureIntent", int.class);
 
     /**
-     * <p>Current state of AWB algorithm</p>
+     * <p>Current state of auto-white balance (AWB) algorithm.</p>
      * <p>Switching between or enabling AWB modes ({@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}) always
      * resets the AWB state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
      * or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -1526,7 +1551,9 @@
      * <p>This is the mode that that is active when
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
      * these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
-     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+     * The scene modes available for a given camera device are listed in
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</p>
      * <p>The interpretation and implementation of these scene modes is left
      * to the implementor of the camera device. Their behavior will not be
      * consistent across all devices, and any given device may only implement
@@ -1534,6 +1561,7 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CaptureRequest#CONTROL_MODE
      * @see #CONTROL_SCENE_MODE_DISABLED
@@ -1559,11 +1587,21 @@
 
     /**
      * <p>Whether video stabilization is
-     * active</p>
+     * active.</p>
+     * <p>Video stabilization automatically translates and scales images from the camera
+     * in order to stabilize motion between consecutive frames.</p>
      * <p>If enabled, video stabilization can modify the
-     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
-     * stabilized</p>
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
+     * <p>Switching between different video stabilization modes may take several frames
+     * to initialize, the camera device will report the current mode in capture result
+     * metadata. For example, When "ON" mode is requested, the video stabilization modes
+     * in the first several capture results may still be "OFF", and it will become "ON"
+     * when the initialization is done.</p>
+     * <p>If a camera device supports both this mode and OIS ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}),
+     * turning both modes on may produce undesirable interaction, so it is recommended not to
+     * enable both at the same time.</p>
      *
+     * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
      * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
@@ -1601,7 +1639,7 @@
      * <p>When set to OFF, the camera device will not fire flash for this capture.</p>
      * <p>When set to SINGLE, the camera device will fire flash regardless of the camera
      * device's auto-exposure routine's result. When used in still capture case, this
-     * control should be used along with AE precapture metering sequence
+     * control should be used along with auto-exposure (AE) precapture metering sequence
      * ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
      * <p>When set to TORCH, the flash will be on continuously. This mode can be used
      * for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
@@ -1690,21 +1728,21 @@
 
     /**
      * <p>Compression quality of the final JPEG
-     * image</p>
-     * <p>85-95 is typical usage range</p>
+     * image.</p>
+     * <p>85-95 is typical usage range.</p>
      */
     public static final Key<Byte> JPEG_QUALITY =
             new Key<Byte>("android.jpeg.quality", byte.class);
 
     /**
      * <p>Compression quality of JPEG
-     * thumbnail</p>
+     * thumbnail.</p>
      */
     public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
             new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
 
     /**
-     * <p>Resolution of embedded JPEG thumbnail</p>
+     * <p>Resolution of embedded JPEG thumbnail.</p>
      * <p>When set to (0, 0) value, the JPEG EXIF will not contain thumbnail,
      * but the captured JPEG will still be a valid image.</p>
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
@@ -1792,7 +1830,7 @@
 
     /**
      * <p>Distance to plane of sharpest focus,
-     * measured from frontmost surface of the lens</p>
+     * measured from frontmost surface of the lens.</p>
      * <p>Should be zero for fixed-focus cameras</p>
      */
     public static final Key<Float> LENS_FOCUS_DISTANCE =
@@ -1800,7 +1838,7 @@
 
     /**
      * <p>The range of scene distances that are in
-     * sharp focus (depth of field)</p>
+     * sharp focus (depth of field).</p>
      * <p>If variable focus not supported, can still report
      * fixed depth of field range</p>
      */
@@ -1810,12 +1848,26 @@
     /**
      * <p>Sets whether the camera device uses optical image stabilization (OIS)
      * when capturing images.</p>
-     * <p>OIS is used to compensate for motion blur due to small movements of
-     * the camera during capture. Unlike digital image stabilization, OIS makes
-     * use of mechanical elements to stabilize the camera sensor, and thus
-     * allows for longer exposure times before camera shake becomes
-     * apparent.</p>
-     * <p>This is not expected to be supported on most devices.</p>
+     * <p>OIS is used to compensate for motion blur due to small
+     * movements of the camera during capture. Unlike digital image
+     * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+     * makes use of mechanical elements to stabilize the camera
+     * sensor, and thus allows for longer exposure times before
+     * camera shake becomes apparent.</p>
+     * <p>Switching between different optical stabilization modes may take several
+     * frames to initialize, the camera device will report the current mode in
+     * capture result metadata. For example, When "ON" mode is requested, the
+     * optical stabilization modes in the first several capture results may still
+     * be "OFF", and it will become "ON" when the initialization is done.</p>
+     * <p>If a camera device supports both OIS and EIS ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}),
+     * turning both modes on may produce undesirable interaction, so it is recommended not
+     * to enable both at the same time.</p>
+     * <p>Not all devices will support OIS; see
+     * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+     * available controls.</p>
+     *
+     * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+     * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
      * @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
      * @see #LENS_OPTICAL_STABILIZATION_MODE_ON
      */
@@ -1859,16 +1911,15 @@
             new Key<Integer>("android.lens.state", int.class);
 
     /**
-     * <p>Mode of operation for the noise reduction
-     * algorithm</p>
+     * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>Noise filtering control. OFF means no noise reduction
      * will be applied by the camera device.</p>
-     * <p>This must be set to a valid mode in
+     * <p>This must be set to a valid mode from
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
      * <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
      * will be applied. HIGH_QUALITY mode indicates that the camera device
      * will use the highest-quality noise filtering algorithms,
-     * even if it slows down capture rate. FAST means the camera device should not
+     * even if it slows down capture rate. FAST means the camera device will not
      * slow down capture rate when applying noise filtering.</p>
      *
      * @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -1934,40 +1985,39 @@
             new Key<Byte>("android.request.pipelineDepth", byte.class);
 
     /**
-     * <p>(x, y, width, height).</p>
-     * <p>A rectangle with the top-level corner of (x,y) and size
-     * (width, height). The region of the sensor that is used for
-     * output. Each stream must use this rectangle to produce its
-     * output, cropping to a smaller region if necessary to
-     * maintain the stream's aspect ratio.</p>
-     * <p>HAL2.x uses only (x, y, width)</p>
-     * <p>The crop region is applied after the RAW to other color space (e.g. YUV)
-     * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage,
-     * it is not croppable. The crop region will be ignored by raw streams.</p>
+     * <p>The region of the sensor to read out for this capture.</p>
+     * <p>The crop region coordinate system is based off
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
+     * top-left corner of the sensor active array.</p>
+     * <p>Output streams use this rectangle to produce their output,
+     * cropping to a smaller region if necessary to maintain the
+     * stream's aspect ratio, then scaling the sensor input to
+     * match the output's configured resolution.</p>
+     * <p>The crop region is applied after the RAW to other color
+     * space (e.g. YUV) conversion. Since raw streams
+     * (e.g. RAW16) don't have the conversion stage, they are not
+     * croppable. The crop region will be ignored by raw streams.</p>
      * <p>For non-raw streams, any additional per-stream cropping will
      * be done to maximize the final pixel area of the stream.</p>
      * <p>For example, if the crop region is set to a 4:3 aspect
-     * ratio, then 4:3 streams should use the exact crop
-     * region. 16:9 streams should further crop vertically
+     * ratio, then 4:3 streams will use the exact crop
+     * region. 16:9 streams will further crop vertically
      * (letterbox).</p>
      * <p>Conversely, if the crop region is set to a 16:9, then 4:3
-     * outputs should crop horizontally (pillarbox), and 16:9
-     * streams should match exactly. These additional crops must
+     * outputs will crop horizontally (pillarbox), and 16:9
+     * streams will match exactly. These additional crops will
      * be centered within the crop region.</p>
-     * <p>The output streams must maintain square pixels at all
-     * times, no matter what the relative aspect ratios of the
-     * crop region and the stream are.  Negative values for
-     * corner are allowed for raw output if full pixel array is
-     * larger than active pixel array. Width and height may be
-     * rounded to nearest larger supportable width, especially
-     * for raw output, where only a few fixed scales may be
-     * possible. The width and height of the crop region cannot
-     * be set to be smaller than floor( activeArraySize.width /
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} ) and floor(
-     * activeArraySize.height /
-     * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom}), respectively.</p>
+     * <p>The width and height of the crop region cannot
+     * be set to be smaller than
+     * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
+     * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+     * <p>The camera device may adjust the crop region to account
+     * for rounding and other hardware requirements; the final
+     * crop region used will be included in the output capture
+     * result.</p>
      *
      * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
     public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
             new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
@@ -2060,21 +2110,42 @@
             new Key<Long>("android.sensor.frameDuration", long.class);
 
     /**
-     * <p>Gain applied to image data. Must be
-     * implemented through analog gain only if set to values
-     * below 'maximum analog sensitivity'.</p>
-     * <p>If the sensor can't apply this exact gain, it should lessen the
-     * gain to the nearest possible value (rather than gain more).</p>
-     * <p>ISO 12232:2006 REI method</p>
+     * <p>The amount of gain applied to sensor data
+     * before processing.</p>
+     * <p>The sensitivity is the standard ISO sensitivity value,
+     * as defined in ISO 12232:2006.</p>
+     * <p>The sensitivity must be within {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}, and
+     * if if it less than {@link CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY android.sensor.maxAnalogSensitivity}, the camera device
+     * is guaranteed to use only analog amplification for applying the gain.</p>
+     * <p>If the camera device cannot apply the exact sensitivity
+     * requested, it will reduce the gain to the nearest supported
+     * value. The final sensitivity used will be available in the
+     * output capture result.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+     * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
      */
     public static final Key<Integer> SENSOR_SENSITIVITY =
             new Key<Integer>("android.sensor.sensitivity", int.class);
 
     /**
      * <p>Time at start of exposure of first
-     * row</p>
-     * <p>Monotonic, should be synced to other timestamps in
-     * system</p>
+     * row of the image sensor active array, in nanoseconds.</p>
+     * <p>The timestamps are also included in all image
+     * buffers produced for the same capture, and will be identical
+     * on all the outputs.</p>
+     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION android.sensor.info.timestampCalibration} <code>==</code> UNCALIBRATED,
+     * the timestamps measure time since an unspecified starting point,
+     * and are monotonically increasing. They can be compared with the
+     * timestamps for other captures from the same camera device, but are
+     * not guaranteed to be comparable to any other time source.</p>
+     * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION android.sensor.info.timestampCalibration} <code>==</code> CALIBRATED,
+     * the timestamps measure time in the same timebase as
+     * android.os.SystemClock#elapsedRealtimeNanos(), and they can be
+     * compared to other timestamps from other subsystems that are using
+     * that base.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
      */
     public static final Key<Long> SENSOR_TIMESTAMP =
             new Key<Long>("android.sensor.timestamp", long.class);
@@ -2150,7 +2221,7 @@
      * <p>When enabled, the sensor sends a test pattern instead of
      * doing a real exposure from the camera.</p>
      * <p>When a test pattern is enabled, all manual sensor controls specified
-     * by android.sensor.* should be ignored. All other controls should
+     * by android.sensor.* will be ignored. All other controls should
      * work as normal.</p>
      * <p>For example, if manual flash is enabled, flash firing should still
      * occur (and that the test pattern remain unmodified, since the flash
@@ -2167,6 +2238,20 @@
             new Key<Integer>("android.sensor.testPatternMode", int.class);
 
     /**
+     * <p>Duration between the start of first row exposure
+     * and the start of last row exposure.</p>
+     * <p>This is the exposure time skew (in the unit of nanosecond) between the first and
+     * last row exposure start times. The first row and the last row are the first
+     * and last rows inside of the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+     * <p>For typical camera sensors that use rolling shutters, this is also equivalent
+     * to the frame readout time.</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     */
+    public static final Key<Long> SENSOR_ROLLING_SHUTTER_SKEW =
+            new Key<Long>("android.sensor.rollingShutterSkew", long.class);
+
+    /**
      * <p>Quality of lens shading correction applied
      * to the image data.</p>
      * <p>When set to OFF mode, no lens shading correction will be applied by the
@@ -2188,7 +2273,7 @@
      * lens shading map data in android.statistics.lensShadingMap, with size specified
      * by android.lens.info.shadingMapSize; the returned shading map data will be the one
      * applied by the camera device for this capture request.</p>
-     * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability
+     * <p>The shading map data may depend on the auto-exposure (AE) and AWB statistics, therefore the reliability
      * of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in
      * AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code> OFF),
      * to get best results, it is recommended that the applications wait for the AE and AWB to
@@ -2205,8 +2290,8 @@
             new Key<Integer>("android.shading.mode", int.class);
 
     /**
-     * <p>State of the face detector
-     * unit</p>
+     * <p>Control for the face detector
+     * unit.</p>
      * <p>Whether face detection is enabled, and whether it
      * should output just the basic fields or the full set of
      * fields. Value must be one of the
@@ -2221,9 +2306,13 @@
             new Key<Integer>("android.statistics.faceDetectMode", int.class);
 
     /**
-     * <p>List of unique IDs for detected
-     * faces</p>
-     * <p>Only available if faceDetectMode == FULL</p>
+     * <p>List of unique IDs for detected faces.</p>
+     * <p>Each detected face is given a unique ID that is valid for as long as the face is visible
+     * to the camera device.  A face that leaves the field of view and later returns may be
+     * assigned a new ID.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+     *
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @hide
      */
     public static final Key<int[]> STATISTICS_FACE_IDS =
@@ -2231,8 +2320,13 @@
 
     /**
      * <p>List of landmarks for detected
-     * faces</p>
-     * <p>Only available if faceDetectMode == FULL</p>
+     * faces.</p>
+     * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @hide
      */
     public static final Key<int[]> STATISTICS_FACE_LANDMARKS =
@@ -2240,8 +2334,13 @@
 
     /**
      * <p>List of the bounding rectangles for detected
-     * faces</p>
-     * <p>Only available if faceDetectMode != OFF</p>
+     * faces.</p>
+     * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+     * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF</p>
+     *
+     * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @hide
      */
     public static final Key<android.graphics.Rect[]> STATISTICS_FACE_RECTANGLES =
@@ -2250,8 +2349,9 @@
     /**
      * <p>List of the face confidence scores for
      * detected faces</p>
-     * <p>Only available if faceDetectMode != OFF. The value should be
-     * meaningful (for example, setting 100 at all times is illegal).</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF.</p>
+     *
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
      * @hide
      */
     public static final Key<byte[]> STATISTICS_FACE_SCORES =
@@ -2370,7 +2470,7 @@
      * applied to that frame.</p>
      * <p>The 4 channel gains are defined in Bayer domain,
      * see {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} for details.</p>
-     * <p>This value should always be calculated by the AWB block,
+     * <p>This value should always be calculated by the auto-white balance (AWB) block,
      * regardless of the android.control.* current values.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
@@ -2396,7 +2496,7 @@
      * that frame.</p>
      * <p>These estimates must be provided for all frames, even if
      * capture settings and color transforms are set by the application.</p>
-     * <p>This value should always be calculated by the AWB block,
+     * <p>This value should always be calculated by the auto-white balance (AWB) block,
      * regardless of the android.control.* current values.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * @deprecated
@@ -2415,12 +2515,13 @@
      * The camera device uses this entry to tell the application what the scene
      * illuminant frequency is.</p>
      * <p>When manual exposure control is enabled
-     * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
-     * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
-     * application can ensure it selects exposure times that do not cause banding
-     * issues by looking into this metadata field. See {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode}
-     * for more details.</p>
-     * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
+     * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} ==
+     * OFF</code>), the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't perform
+     * antibanding, and the application can ensure it selects
+     * exposure times that do not cause banding issues by looking
+     * into this metadata field. See
+     * {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} for more details.</p>
+     * <p>Reports NONE if there doesn't appear to be flickering illumination.</p>
      *
      * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
      * @see CaptureRequest#CONTROL_AE_MODE
@@ -2435,7 +2536,7 @@
     /**
      * <p>Operating mode for hotpixel map generation.</p>
      * <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
-     * If set to OFF, no hotpixel map should be returned.</p>
+     * If set to OFF, no hotpixel map will be returned.</p>
      * <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
      *
      * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -2463,7 +2564,7 @@
      * <p>Whether the camera device will output the lens
      * shading map in output result metadata.</p>
      * <p>When set to ON,
-     * android.statistics.lensShadingMap must be provided in
+     * android.statistics.lensShadingMap will be provided in
      * the output result metadata.</p>
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/package.html b/core/java/android/hardware/camera2/package.html
index 9f6c2a9..ef0d7bd 100644
--- a/core/java/android/hardware/camera2/package.html
+++ b/core/java/android/hardware/camera2/package.html
@@ -34,49 +34,71 @@
 CameraDevices} provide a set of static property information that
 describes the hardware device and the available settings and output
 parameters for the device. This information is provided through the
-{@link android.hardware.camera2.CameraCharacteristics} object.</p>
+{@link android.hardware.camera2.CameraCharacteristics} object, and is
+available through {@link
+android.hardware.camera2.CameraManager#getCameraCharacteristics}</p>
 
 <p>To capture or stream images from a camera device, the application
-must first configure a set of output Surfaces for use with the camera
-device, with {@link
-android.hardware.camera2.CameraDevice#configureOutputs}. Each
-Surface has to be pre-configured with an appropriate size and format
-(if applicable) to match the sizes and formats available from the
-camera device. A target Surface can be obtained from a variety of
-classes, including {@link android.view.SurfaceView}, {@link
-android.graphics.SurfaceTexture} via {@link
-android.view.Surface#Surface(SurfaceTexture), {@link
-android.media.MediaCodec}, and {@link android.media.ImageReader}.
+must first create a {@link
+android.hardware.camera2.CameraCaptureSession camera capture session}
+with a set of output Surfaces for use with the camera device, with
+{@link
+android.hardware.camera2.CameraDevice#createCaptureSession}. Each
+Surface has to be pre-configured with an {@link
+android.hardware.camera2.params.StreamConfigurationMap appropriate
+size and format} (if applicable) to match the sizes and formats
+available from the camera device. A target Surface can be obtained
+from a variety of classes, including {@link android.view.SurfaceView},
+{@link android.graphics.SurfaceTexture} via
+{@link android.view.Surface#Surface(SurfaceTexture)},
+{@link android.media.MediaCodec}, {@link android.media.MediaRecorder},
+{@link android.renderscript.Allocation}, and {@link android.media.ImageReader}.
 </p>
 
+<p>Generally, camera preview images are sent to {@link
+android.view.SurfaceView} or {@link android.view.TextureView} (via its
+{@link android.graphics.SurfaceTexture}). Capture of JPEG images or
+RAW buffers for {@link android.hardware.camera2.DngCreator} can be done
+with {@link android.media.ImageReader} with the
+{android.graphics.ImageFormat#JPEG} and
+{android.graphics.ImageFormat#RAW_SENSOR} formats.  Application-driven
+processing of camera data in RenderScript, OpenGL ES, or directly in
+managed or native code is best done through {@link
+android.renderscript.Allocation} with a YUV {@link
+android.renderscript.Type}, {@link android.graphics.SurfaceTexture},
+and {@link android.media.ImageReader} with a
+{android.graphics.ImageFormat#YUV_420_888} format, respectively.</p>
+
 <p>The application then needs to construct a {@link
 android.hardware.camera2.CaptureRequest}, which defines all the
 capture parameters needed by a camera device to capture a single
 image. The request also lists which of the configured output Surfaces
 should be used as targets for this capture. The CameraDevice has a
 {@link android.hardware.camera2.CameraDevice#createCaptureRequest
-convenience factory method} for creating a request for a given use
-case which is optimized for the Android device the application is
-running on.</p>
+factory method} for creating a {@link
+android.hardware.camera2.CaptureRequest.Builder request builder} for a
+given use case, which is optimized for the Android device the
+application is running on.</p>
 
-<p>Once the request has been set up, it can be handed to the
-CameraDevice either for a one-shot {@link
-android.hardware.camera2.CameraDevice#capture} or for an endlessly
-{@link android.hardware.camera2.CameraDevice#setRepeatingRequest
-repeating} use. Both methods also accept a list of requests to use as
-a burst capture / repeating burst. Repeating requests have a lower
-priority than captures, so a request submitted
+<p>Once the request has been set up, it can be handed to the active
+capture session either for a one-shot {@link
+android.hardware.camera2.CameraCaptureSession#capture capture} or for
+an endlessly {@link
+android.hardware.camera2.CameraCaptureSession#setRepeatingRequest
+repeating} use. Both methods also have a variant that accepts a list
+of requests to use as a burst capture / repeating burst. Repeating
+requests have a lower priority than captures, so a request submitted
 through <code>capture()</code> while there's a repeating request
-configured will be captured as soon as the current repeat (burst)
-capture completes.</p>
+configured will be captured before any new instances of the currently
+repeating (burst) capture will begin capture.</p>
 
 <p>After processing a request, the camera device will produce a {@link
-android.hardware.camera2.CaptureResult} object, which contains
+android.hardware.camera2.TotalCaptureResult} object, which contains
 information about the state of the camera device at time of capture,
 and the final settings used. These may vary somewhat from the request,
 if rounding or resolving contradictory parameters was necessary. The
 camera device will also send a frame of image data into each of the
-output streams included in the request. These are produced
+output {@code Surfaces} included in the request. These are produced
 asynchronously relative to the output CaptureResult, sometimes
 substantially later.</p>
 
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index 1c6b6e9..a6fc10f 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -28,8 +28,9 @@
 
 /**
  * Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to set up
+ * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
+ * with {@link CameraDevice#createCaptureSession}.
  * <!-- TODO: link to input stream configuration -->
  *
  * <p>This is the authoritative list for all input/output formats (and sizes respectively
@@ -124,7 +125,7 @@
      *
      * @return {@code true} if output configuration, {@code false} otherwise
      *
-     * @see CameraDevice#configureOutputs
+     * @see CameraDevice#createCaptureSession
      */
     public boolean isOutput() {
         return !mInput;
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 4cd6d15..3036425 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -34,8 +34,10 @@
 
 /**
  * Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraCaptureSession capture session} with
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
  * <!-- TODO: link to input stream configuration -->
  *
  * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
@@ -56,7 +58,7 @@
  * }</code></pre>
  *
  * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
- * @see CameraDevice#configureOutputs
+ * @see CameraDevice#createCaptureSession
  */
 public final class StreamConfigurationMap {
 
@@ -155,8 +157,8 @@
     }
 
     /**
-     * Determine whether or not output streams can be
-     * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
+     * Determine whether or not output surfaces with a particular user-defined format can be passed
+     * {@link CameraDevice#createCaptureSession createCaptureSession}.
      *
      * <p>This method determines that the output {@code format} is supported by the camera device;
      * each output {@code surface} target may or may not itself support that {@code format}.
@@ -168,7 +170,7 @@
      * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
      * @return
      *          {@code true} iff using a {@code surface} with this {@code format} will be
-     *          supported with {@link CameraDevice#configureOutputs}
+     *          supported with {@link CameraDevice#createCaptureSession}
      *
      * @throws IllegalArgumentException
      *          if the image format was not a defined named constant
@@ -176,7 +178,7 @@
      *
      * @see ImageFormat
      * @see PixelFormat
-     * @see CameraDevice#configureOutputs
+     * @see CameraDevice#createCaptureSession
      */
     public boolean isOutputSupportedFor(int format) {
         checkArgumentFormat(format);
@@ -210,7 +212,7 @@
      *
      * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
      * provide a producer endpoint that is suitable to be used with
-     * {@link CameraDevice#configureOutputs}.</p>
+     * {@link CameraDevice#createCaptureSession}.</p>
      *
      * <p>Since not all of the above classes support output of all format and size combinations,
      * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
@@ -220,7 +222,7 @@
      *
      * @throws NullPointerException if {@code klass} was {@code null}
      *
-     * @see CameraDevice#configureOutputs
+     * @see CameraDevice#createCaptureSession
      * @see #isOutputSupportedFor(Surface)
      */
     public static <T> boolean isOutputSupportedFor(Class<T> klass) {
@@ -244,8 +246,8 @@
     }
 
     /**
-     * Determine whether or not the {@code surface} in its current state is suitable to be
-     * {@link CameraDevice#configureOutputs configured} as an output.
+     * Determine whether or not the {@code surface} in its current state is suitable to be included
+     * in a {@link CameraDevice#createCaptureSession capture session} as an output.
      *
      * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
      * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
@@ -269,7 +271,7 @@
      *
      * @throws NullPointerException if {@code surface} was {@code null}
      *
-     * @see CameraDevice#configureOutputs
+     * @see CameraDevice#createCaptureSession
      * @see #isOutputSupportedFor(Class)
      */
     public boolean isOutputSupportedFor(Surface surface) {
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
similarity index 89%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
index 1f25439..1615910 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.hardware.hdmi;
 
-parcelable Task;
- 
\ No newline at end of file
+parcelable HdmiCecDeviceInfo;
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/hardware/hdmi/HdmiPortInfo.aidl
similarity index 90%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/hardware/hdmi/HdmiPortInfo.aidl
index 1f25439..157b5b3 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.aidl
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package android.hardware.hdmi;
 
-parcelable Task;
- 
\ No newline at end of file
+parcelable HdmiPortInfo;
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
new file mode 100644
index 0000000..7b25f8a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.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.hardware.hdmi;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to encapsulate HDMI port information. Contains the capability of the ports such as
+ * HDMI-CEC, MHL, ARC(Audio Return Channel), and physical address assigned to each port.
+ *
+ * @hide
+ */
+@SystemApi
+public final class HdmiPortInfo implements Parcelable {
+    /** HDMI port type: Input */
+    public static final int PORT_INPUT = 0;
+
+    /** HDMI port type: Output */
+    public static final int PORT_OUTPUT = 1;
+
+    private final int mId;
+    private final int mType;
+    private final int mAddress;
+    private final boolean mCecSupported;
+    private final boolean mArcSupported;
+    private final boolean mMhlSupported;
+
+    /**
+     * Constructor.
+     *
+     * @param id identifier assigned to each port. 1 for HDMI port 1
+     * @param type HDMI port input/output type
+     * @param address physical address of the port
+     * @param cec {@code true} if HDMI-CEC is supported on the port
+     * @param mhl {@code true} if MHL is supported on the port
+     * @param arc {@code true} if audio return channel is supported on the port
+     */
+    public HdmiPortInfo(int id, int type, int address, boolean cec, boolean mhl, boolean arc) {
+        mId = id;
+        mType = type;
+        mAddress = address;
+        mCecSupported = cec;
+        mArcSupported = arc;
+        mMhlSupported = mhl;
+    }
+
+    /**
+     * Returns the port id.
+     *
+     * @return port id
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the port type.
+     *
+     * @return port type
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the port address.
+     *
+     * @return port address
+     */
+    public int getAddress() {
+        return mAddress;
+    }
+
+    /**
+     * Returns {@code true} if the port supports HDMI-CEC signaling.
+     *
+     * @return {@code true} if the port supports HDMI-CEC signaling.
+     */
+    public boolean isCecSupported() {
+        return mCecSupported;
+    }
+
+    /**
+     * Returns {@code true} if the port supports MHL signaling.
+     *
+     * @return {@code true} if the port supports MHL signaling.
+     */
+    public boolean isMhlSupported() {
+        return mMhlSupported;
+    }
+
+    /**
+     * Returns {@code true} if the port supports audio return channel.
+     *
+     * @return {@code true} if the port supports audio return channel
+     */
+    public boolean isArcSupported() {
+        return mArcSupported;
+    }
+
+    /**
+     * Describe the kinds of special objects contained in this Parcelable's
+     * marshalled representation.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+
+    /**
+     * A helper class to deserialize {@link HdmiPortInfo} for a parcel.
+     */
+    public static final Parcelable.Creator<HdmiPortInfo> CREATOR =
+            new Parcelable.Creator<HdmiPortInfo>() {
+                @Override
+                public HdmiPortInfo createFromParcel(Parcel source) {
+                    int id = source.readInt();
+                    int type = source.readInt();
+                    int address = source.readInt();
+                    boolean cec = (source.readInt() == 1);
+                    boolean arc = (source.readInt() == 1);
+                    boolean mhl = (source.readInt() == 1);
+                    return new HdmiPortInfo(id, type, address, cec, arc, mhl);
+                }
+
+                @Override
+                public HdmiPortInfo[] newArray(int size) {
+                    return new HdmiPortInfo[size];
+                }
+            };
+
+    /**
+     * Serialize this object into a {@link Parcel}.
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *        May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mId);
+        dest.writeInt(mType);
+        dest.writeInt(mAddress);
+        dest.writeInt(mCecSupported ? 1 : 0);
+        dest.writeInt(mArcSupported ? 1 : 0);
+        dest.writeInt(mMhlSupported ? 1 : 0);
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 6dc4a4f..85af3d1 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -16,6 +16,8 @@
 package android.hardware.hdmi;
 
 import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.util.Log;
 
 /**
  * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
@@ -33,4 +35,46 @@
     HdmiTvClient(IHdmiControlService service) {
         mService = service;
     }
+
+    // Factory method for HdmiTvClient.
+    // Declared package-private. Accessed by HdmiControlManager only.
+    static HdmiTvClient create(IHdmiControlService service) {
+        return new HdmiTvClient(service);
+    }
+
+    /**
+     * Callback interface used to get the result of {@link #deviceSelect}.
+     */
+    public interface SelectCallback {
+        /**
+         * Called when the operation is finished.
+         *
+         * @param result the result value of {@link #deviceSelect}
+         */
+        void onComplete(int result);
+    }
+
+    /**
+     * Select a CEC logical device to be a new active source.
+     *
+     * @param logicalAddress
+     * @param callback
+     */
+    public void deviceSelect(int logicalAddress, SelectCallback callback) {
+        // TODO: Replace SelectCallback with PartialResult.
+        try {
+            mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to select device: ", e);
+        }
+    }
+
+    private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+        return new IHdmiControlCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+                callback.onComplete(result);
+            }
+        };
+    }
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 8da38e1..559a469 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -16,10 +16,14 @@
 
 package android.hardware.hdmi;
 
-import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
 
+import java.util.List;
+
 /**
  * Binder interface that clients running in the application process
  * will use to perform HDMI-CEC features by communicating with other devices
@@ -33,4 +37,9 @@
     void queryDisplayStatus(IHdmiControlCallback callback);
     void addHotplugEventListener(IHdmiHotplugEventListener listener);
     void removeHotplugEventListener(IHdmiHotplugEventListener listener);
+    void addDeviceEventListener(IHdmiDeviceEventListener listener);
+    void deviceSelect(int logicalAddress, IHdmiControlCallback callback);
+    void portSelect(int portId, IHdmiControlCallback callback);
+    void sendKeyEvent(int keyCode, boolean isPressed);
+    List<HdmiPortInfo> getPortInfo();
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
new file mode 100644
index 0000000..c4e5989
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+
+/**
+ * Callback interface definition for HDMI client to get informed of
+ * the CEC logical device status change event.
+ *
+ * @hide
+ */
+oneway interface IHdmiDeviceEventListener {
+
+    /**
+     * @param deviceInfo {@link HdmiCecDeviceInfo} of the logical device whose
+     *                   status has changed
+     * @param activated true if the device gets activated
+     */
+    void onStatusChanged(in HdmiCecDeviceInfo deviceInfo, in boolean activated);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 27402668..ba31243 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -429,6 +429,11 @@
      */
     public final static int INVALID_NET_ID = 0;
 
+    /**
+     * @hide
+     */
+    public final static int REQUEST_ID_UNSET = 0;
+
     private final IConnectivityManager mService;
 
     private final String mPackageName;
@@ -863,10 +868,10 @@
             return -1;
         }
 
-        NetworkRequest request = removeRequestForFeature(netCap);
-        if (request != null) {
+        NetworkCallback networkCallback = removeRequestForFeature(netCap);
+        if (networkCallback != null) {
             Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature);
-            releaseNetworkRequest(request);
+            unregisterNetworkCallback(networkCallback);
         }
         return 1;
     }
@@ -883,8 +888,8 @@
      * @hide
      */
     public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) {
-        for (Integer capability : nc.getNetworkCapabilities()) {
-            switch (capability.intValue()) {
+        for (int capability : nc.getCapabilities()) {
+            switch (capability) {
                 case NetworkCapabilities.NET_CAPABILITY_CBS:
                 case NetworkCapabilities.NET_CAPABILITY_DUN:
                 case NetworkCapabilities.NET_CAPABILITY_EIMS:
@@ -903,7 +908,7 @@
         }
         // All the capabilities are typically provided by restricted networks.
         // Conclude that this network is restricted.
-        nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
     }
 
     private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
@@ -927,15 +932,14 @@
                 return null;
             }
             NetworkCapabilities netCap = new NetworkCapabilities();
-            netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-            netCap.addNetworkCapability(cap);
+            netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
             maybeMarkCapabilitiesRestricted(netCap);
             return netCap;
         } else if (networkType == TYPE_WIFI) {
             if ("p2p".equals(feature)) {
                 NetworkCapabilities netCap = new NetworkCapabilities();
                 netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-                netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+                netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
                 maybeMarkCapabilitiesRestricted(netCap);
                 return netCap;
             }
@@ -978,15 +982,15 @@
         int expireSequenceNumber;
         Network currentNetwork;
         int delay = -1;
-        NetworkCallbackListener networkCallbackListener = new NetworkCallbackListener() {
+        NetworkCallback networkCallback = new NetworkCallback() {
             @Override
-            public void onAvailable(NetworkRequest request, Network network) {
+            public void onAvailable(Network network) {
                 currentNetwork = network;
                 Log.d(TAG, "startUsingNetworkFeature got Network:" + network);
                 setProcessDefaultNetworkForHostResolution(network);
             }
             @Override
-            public void onLost(NetworkRequest request, Network network) {
+            public void onLost(Network network) {
                 if (network.equals(currentNetwork)) {
                     currentNetwork = null;
                     setProcessDefaultNetworkForHostResolution(null);
@@ -1020,7 +1024,7 @@
             if (l == null) return;
             ourSeqNum = l.expireSequenceNumber;
             if (l.expireSequenceNumber == sequenceNum) {
-                releaseNetworkRequest(l.networkRequest);
+                unregisterNetworkCallback(l.networkCallback);
                 sLegacyRequests.remove(netCap);
             }
         }
@@ -1037,7 +1041,7 @@
         l.networkCapabilities = netCap;
         l.delay = delay;
         l.expireSequenceNumber = 0;
-        l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0,
+        l.networkRequest = sendRequestForNetwork(netCap, l.networkCallback, 0,
                 REQUEST, type);
         if (l.networkRequest == null) return null;
         sLegacyRequests.put(netCap, l);
@@ -1053,11 +1057,11 @@
         }
     }
 
-    private NetworkRequest removeRequestForFeature(NetworkCapabilities netCap) {
+    private NetworkCallback removeRequestForFeature(NetworkCapabilities netCap) {
         synchronized (sLegacyRequests) {
             LegacyRequest l = sLegacyRequests.remove(netCap);
             if (l == null) return null;
-            return l.networkRequest;
+            return l.networkCallback;
         }
     }
 
@@ -1180,8 +1184,8 @@
     }
 
     /**
-     * Callback for use with {@link ConnectivityManager#registerNetworkActiveListener} to
-     * find out when the current network has gone in to a high power state.
+     * Callback for use with {@link ConnectivityManager#registerDefaultNetworkActiveListener}
+     * to find out when the system default network has gone in to a high power state.
      */
     public interface OnNetworkActiveListener {
         /**
@@ -1190,7 +1194,7 @@
          * operations.  Note that this listener only tells you when the network becomes
          * active; if at any other time you want to know whether it is active (and thus okay
          * to initiate network traffic), you can retrieve its instantaneous state with
-         * {@link ConnectivityManager#isNetworkActive}.
+         * {@link ConnectivityManager#isDefaultNetworkActive}.
          */
         public void onNetworkActive();
     }
@@ -1211,13 +1215,18 @@
                     = new ArrayMap<OnNetworkActiveListener, INetworkActivityListener>();
 
     /**
-     * Start listening to reports when the data network is active, meaning it is
-     * a good time to perform network traffic.  Use {@link #isNetworkActive()}
-     * to determine the current state of the network after registering the listener.
+     * Start listening to reports when the system's default data network is active, meaning it is
+     * a good time to perform network traffic.  Use {@link #isDefaultNetworkActive()}
+     * to determine the current state of the system's default network after registering the
+     * listener.
+     * <p>
+     * If the process default network has been set with
+     * {@link ConnectivityManager#setProcessDefaultNetwork} this function will not
+     * reflect the process's default, but the system default.
      *
      * @param l The listener to be told when the network is active.
      */
-    public void registerNetworkActiveListener(final OnNetworkActiveListener l) {
+    public void registerDefaultNetworkActiveListener(final OnNetworkActiveListener l) {
         INetworkActivityListener rl = new INetworkActivityListener.Stub() {
             @Override
             public void onNetworkActive() throws RemoteException {
@@ -1234,11 +1243,11 @@
 
     /**
      * Remove network active listener previously registered with
-     * {@link #registerNetworkActiveListener}.
+     * {@link #registerDefaultNetworkActiveListener}.
      *
      * @param l Previously registered listener.
      */
-    public void unregisterNetworkActiveListener(OnNetworkActiveListener l) {
+    public void unregisterDefaultNetworkActiveListener(OnNetworkActiveListener l) {
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
         if (rl == null) {
             throw new IllegalArgumentException("Listener not registered: " + l);
@@ -1257,7 +1266,7 @@
      * this state.  This method tells you whether right now is currently a good time to
      * initiate network traffic, as the network is already active.
      */
-    public boolean isNetworkActive() {
+    public boolean isDefaultNetworkActive() {
         try {
             return getNetworkManagementService().isNetworkActive();
         } catch (RemoteException e) {
@@ -1889,7 +1898,7 @@
      * Base class for NetworkRequest callbacks.  Used for notifications about network
      * changes.  Should be extended by applications wanting notifications.
      */
-    public static class NetworkCallbackListener {
+    public static class NetworkCallback {
         /** @hide */
         public static final int PRECHECK     = 1;
         /** @hide */
@@ -1912,78 +1921,68 @@
          * Called whenever the framework connects to a network that it may use to
          * satisfy this request
          */
-        public void onPreCheck(NetworkRequest networkRequest, Network network) {}
+        public void onPreCheck(Network network) {}
 
         /**
          * Called when the framework connects and has declared new network ready for use.
+         * This callback may be called more than once if the {@link Network} that is
+         * satisfying the request changes.
          *
-         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
          * @param network The {@link Network} of the satisfying network.
          */
-        public void onAvailable(NetworkRequest networkRequest, Network network) {}
+        public void onAvailable(Network network) {}
 
         /**
          * Called when the network is about to be disconnected.  Often paired with an
-         * {@link NetworkCallbackListener#onAvailable} call with the new replacement network
+         * {@link NetworkCallback#onAvailable} call with the new replacement network
          * for graceful handover.  This may not be called if we have a hard loss
          * (loss without warning).  This may be followed by either a
-         * {@link NetworkCallbackListener#onLost} call or a
-         * {@link NetworkCallbackListener#onAvailable} call for this network depending
+         * {@link NetworkCallback#onLost} call or a
+         * {@link NetworkCallback#onAvailable} call for this network depending
          * on whether we lose or regain it.
          *
-         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
-         * @param network The {@link Network} of the failing network.
-         * @param maxSecToLive The time in seconds the framework will attempt to keep the
-         *                     network connected.  Note that the network may suffers a
+         * @param network The {@link Network} that is about to be disconnected.
+         * @param maxMsToLive The time in ms the framework will attempt to keep the
+         *                     network connected.  Note that the network may suffer a
          *                     hard loss at any time.
          */
-        public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
+        public void onLosing(Network network, int maxMsToLive) {}
 
         /**
          * Called when the framework has a hard loss of the network or when the
          * graceful failure ends.
          *
-         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
          * @param network The {@link Network} lost.
          */
-        public void onLost(NetworkRequest networkRequest, Network network) {}
+        public void onLost(Network network) {}
 
         /**
          * Called if no network is found in the given timeout time.  If no timeout is given,
          * this will not be called.
          * @hide
          */
-        public void onUnavailable(NetworkRequest networkRequest) {}
+        public void onUnavailable() {}
 
         /**
          * Called when the network the framework connected to for this request
          * changes capabilities but still satisfies the stated need.
          *
-         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
          * @param network The {@link Network} whose capabilities have changed.
          * @param networkCapabilities The new {@link NetworkCapabilities} for this network.
          */
-        public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
+        public void onCapabilitiesChanged(Network network,
                 NetworkCapabilities networkCapabilities) {}
 
         /**
          * Called when the network the framework connected to for this request
          * changes {@link LinkProperties}.
          *
-         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
          * @param network The {@link Network} whose link properties have changed.
          * @param linkProperties The new {@link LinkProperties} for this network.
          */
-        public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
-                LinkProperties linkProperties) {}
+        public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {}
 
-        /**
-         * Called when a {@link #releaseNetworkRequest} call concludes and the registered
-         * callbacks will no longer be used.
-         *
-         * @param networkRequest The {@link NetworkRequest} used to initiate the request.
-         */
-        public void onReleased(NetworkRequest networkRequest) {}
+        private NetworkRequest networkRequest;
     }
 
     private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
@@ -2009,12 +2008,12 @@
     private static final int EXPIRE_LEGACY_REQUEST      = BASE + 10;
 
     private class CallbackHandler extends Handler {
-        private final HashMap<NetworkRequest, NetworkCallbackListener>mCallbackMap;
+        private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
         private final AtomicInteger mRefCount;
         private static final String TAG = "ConnectivityManager.CallbackHandler";
         private final ConnectivityManager mCm;
 
-        CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbackListener>callbackMap,
+        CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallback>callbackMap,
                 AtomicInteger refCount, ConnectivityManager cm) {
             super(looper);
             mCallbackMap = callbackMap;
@@ -2028,9 +2027,9 @@
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbackListener callbacks = getCallbacks(request);
+                    NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onPreCheck(request, getNetwork(message));
+                        callbacks.onPreCheck(getNetwork(message));
                     } else {
                         Log.e(TAG, "callback not found for PRECHECK message");
                     }
@@ -2038,9 +2037,9 @@
                 }
                 case CALLBACK_AVAILABLE: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbackListener callbacks = getCallbacks(request);
+                    NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onAvailable(request, getNetwork(message));
+                        callbacks.onAvailable(getNetwork(message));
                     } else {
                         Log.e(TAG, "callback not found for AVAILABLE message");
                     }
@@ -2048,9 +2047,9 @@
                 }
                 case CALLBACK_LOSING: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbackListener callbacks = getCallbacks(request);
+                    NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onLosing(request, getNetwork(message), message.arg1);
+                        callbacks.onLosing(getNetwork(message), message.arg1);
                     } else {
                         Log.e(TAG, "callback not found for LOSING message");
                     }
@@ -2058,9 +2057,9 @@
                 }
                 case CALLBACK_LOST: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbackListener callbacks = getCallbacks(request);
+                    NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onLost(request, getNetwork(message));
+                        callbacks.onLost(getNetwork(message));
                     } else {
                         Log.e(TAG, "callback not found for LOST message");
                     }
@@ -2068,12 +2067,12 @@
                 }
                 case CALLBACK_UNAVAIL: {
                     NetworkRequest req = (NetworkRequest)message.obj;
-                    NetworkCallbackListener callbacks = null;
+                    NetworkCallback callbacks = null;
                     synchronized(mCallbackMap) {
                         callbacks = mCallbackMap.get(req);
                     }
                     if (callbacks != null) {
-                        callbacks.onUnavailable(req);
+                        callbacks.onUnavailable();
                     } else {
                         Log.e(TAG, "callback not found for UNAVAIL message");
                     }
@@ -2081,12 +2080,12 @@
                 }
                 case CALLBACK_CAP_CHANGED: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbackListener callbacks = getCallbacks(request);
+                    NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         Network network = getNetwork(message);
                         NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
 
-                        callbacks.onNetworkCapabilitiesChanged(request, network, cap);
+                        callbacks.onCapabilitiesChanged(network, cap);
                     } else {
                         Log.e(TAG, "callback not found for CHANGED message");
                     }
@@ -2094,12 +2093,12 @@
                 }
                 case CALLBACK_IP_CHANGED: {
                     NetworkRequest request = getNetworkRequest(message);
-                    NetworkCallbackListener callbacks = getCallbacks(request);
+                    NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
                         Network network = getNetwork(message);
                         LinkProperties lp = mCm.getLinkProperties(network);
 
-                        callbacks.onLinkPropertiesChanged(request, network, lp);
+                        callbacks.onLinkPropertiesChanged(network, lp);
                     } else {
                         Log.e(TAG, "callback not found for CHANGED message");
                     }
@@ -2107,20 +2106,19 @@
                 }
                 case CALLBACK_RELEASED: {
                     NetworkRequest req = (NetworkRequest)message.obj;
-                    NetworkCallbackListener callbacks = null;
+                    NetworkCallback callbacks = null;
                     synchronized(mCallbackMap) {
                         callbacks = mCallbackMap.remove(req);
                     }
                     if (callbacks != null) {
-                        callbacks.onReleased(req);
+                        synchronized(mRefCount) {
+                            if (mRefCount.decrementAndGet() == 0) {
+                                getLooper().quit();
+                            }
+                        }
                     } else {
                         Log.e(TAG, "callback not found for CANCELED message");
                     }
-                    synchronized(mRefCount) {
-                        if (mRefCount.decrementAndGet() == 0) {
-                            getLooper().quit();
-                        }
-                    }
                     break;
                 }
                 case CALLBACK_EXIT: {
@@ -2138,7 +2136,7 @@
         private NetworkRequest getNetworkRequest(Message msg) {
             return (NetworkRequest)(msg.obj);
         }
-        private NetworkCallbackListener getCallbacks(NetworkRequest req) {
+        private NetworkCallback getCallbacks(NetworkRequest req) {
             synchronized(mCallbackMap) {
                 return mCallbackMap.get(req);
             }
@@ -2146,7 +2144,7 @@
         private Network getNetwork(Message msg) {
             return new Network(msg.arg2);
         }
-        private NetworkCallbackListener removeCallbacks(Message msg) {
+        private NetworkCallback removeCallbacks(Message msg) {
             NetworkRequest req = (NetworkRequest)msg.obj;
             synchronized(mCallbackMap) {
                 return mCallbackMap.remove(req);
@@ -2154,19 +2152,19 @@
         }
     }
 
-    private void addCallbackListener() {
+    private void incCallbackHandlerRefCount() {
         synchronized(sCallbackRefCount) {
             if (sCallbackRefCount.incrementAndGet() == 1) {
                 // TODO - switch this over to a ManagerThread or expire it when done
                 HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
                 callbackThread.start();
                 sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
-                        sNetworkCallbackListener, sCallbackRefCount, this);
+                        sNetworkCallback, sCallbackRefCount, this);
             }
         }
     }
 
-    private void removeCallbackListener() {
+    private void decCallbackHandlerRefCount() {
         synchronized(sCallbackRefCount) {
             if (sCallbackRefCount.decrementAndGet() == 0) {
                 sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget();
@@ -2175,8 +2173,8 @@
         }
     }
 
-    static final HashMap<NetworkRequest, NetworkCallbackListener> sNetworkCallbackListener =
-            new HashMap<NetworkRequest, NetworkCallbackListener>();
+    static final HashMap<NetworkRequest, NetworkCallback> sNetworkCallback =
+            new HashMap<NetworkRequest, NetworkCallback>();
     static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
     static CallbackHandler sCallbackHandler = null;
 
@@ -2184,51 +2182,48 @@
     private final static int REQUEST = 2;
 
     private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
-            NetworkCallbackListener networkCallbackListener, int timeoutSec, int action,
+            NetworkCallback networkCallback, int timeoutSec, int action,
             int legacyType) {
-        NetworkRequest networkRequest = null;
-        if (networkCallbackListener == null) {
-            throw new IllegalArgumentException("null NetworkCallbackListener");
+        if (networkCallback == null) {
+            throw new IllegalArgumentException("null NetworkCallback");
         }
         if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
         try {
-            addCallbackListener();
+            incCallbackHandlerRefCount();
             if (action == LISTEN) {
-                networkRequest = mService.listenForNetwork(need, new Messenger(sCallbackHandler),
-                        new Binder());
+                networkCallback.networkRequest = mService.listenForNetwork(need,
+                        new Messenger(sCallbackHandler), new Binder());
             } else {
-                networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
-                        timeoutSec, new Binder(), legacyType);
+                networkCallback.networkRequest = mService.requestNetwork(need,
+                        new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
             }
-            if (networkRequest != null) {
-                synchronized(sNetworkCallbackListener) {
-                    sNetworkCallbackListener.put(networkRequest, networkCallbackListener);
+            if (networkCallback.networkRequest != null) {
+                synchronized(sNetworkCallback) {
+                    sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
                 }
             }
         } catch (RemoteException e) {}
-        if (networkRequest == null) removeCallbackListener();
-        return networkRequest;
+        if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
+        return networkCallback.networkRequest;
     }
 
     /**
      * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
      * This {@link NetworkRequest} will live until released via
-     * {@link #releaseNetworkRequest} or the calling application exits.
+     * {@link #unregisterNetworkCallback} or the calling application exits.
      * Status of the request can be followed by listening to the various
-     * callbacks described in {@link NetworkCallbackListener}.  The {@link Network}
+     * callbacks described in {@link NetworkCallback}.  The {@link Network}
      * can be used to direct traffic to the network.
      *
-     * @param need {@link NetworkCapabilities} required by this request.
-     * @param networkCallbackListener The {@link NetworkCallbackListener} to be utilized for this
-     *                         request.  Note the callbacks can be shared by multiple
-     *                         requests and the NetworkRequest token utilized to
-     *                         determine to which request the callback relates.
-     * @return A {@link NetworkRequest} object identifying the request.
+     * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this
+     *                        request.  Note the callback must not be shared - they
+     *                        uniquely specify this request.
      */
-    public NetworkRequest requestNetwork(NetworkCapabilities need,
-            NetworkCallbackListener networkCallbackListener) {
-        return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE);
+    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
+        sendRequestForNetwork(request.networkCapabilities, networkCallback, 0,
+                REQUEST, TYPE_NONE);
     }
 
     /**
@@ -2236,53 +2231,53 @@
      * by a timeout.
      *
      * This function behaves identically to the non-timedout version, but if a suitable
-     * network is not found within the given time (in Seconds) the
-     * {@link NetworkCallbackListener#unavailable} callback is called.  The request must
+     * network is not found within the given time (in milliseconds) the
+     * {@link NetworkCallback#unavailable} callback is called.  The request must
      * still be released normally by calling {@link releaseNetworkRequest}.
-     * @param need {@link NetworkCapabilities} required by this request.
-     * @param networkCallbackListener The callbacks to be utilized for this request.  Note
-     *                         the callbacks can be shared by multiple requests and
-     *                         the NetworkRequest token utilized to determine to which
-     *                         request the callback relates.
-     * @param timeoutSec The time in seconds to attempt looking for a suitable network
-     *                   before {@link NetworkCallbackListener#unavailable} is called.
-     * @return A {@link NetworkRequest} object identifying the request.
+     * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The callbacks to be utilized for this request.  Note
+     *                        the callbacks must not be shared - they uniquely specify
+     *                        this request.
+     * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+     *                  before {@link NetworkCallback#unavailable} is called.
      * @hide
      */
-    public NetworkRequest requestNetwork(NetworkCapabilities need,
-            NetworkCallbackListener networkCallbackListener, int timeoutSec) {
-        return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST,
-                TYPE_NONE);
+    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+            int timeoutMs) {
+        sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs,
+                REQUEST, TYPE_NONE);
     }
 
     /**
-     * The maximum number of seconds the framework will look for a suitable network
+     * The maximum number of milliseconds the framework will look for a suitable network
      * during a timeout-equiped call to {@link requestNetwork}.
      * {@hide}
      */
-    public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
+    public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000;
 
     /**
      * The lookup key for a {@link Network} object included with the intent after
      * succesfully finding a network for the applications request.  Retrieve it with
      * {@link android.content.Intent#getParcelableExtra(String)}.
+     * @hide
      */
     public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
 
     /**
-     * The lookup key for a {@link NetworkCapabilities} object included with the intent after
+     * The lookup key for a {@link NetworkRequest} object included with the intent after
      * succesfully finding a network for the applications request.  Retrieve it with
      * {@link android.content.Intent#getParcelableExtra(String)}.
+     * @hide
      */
-    public static final String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES =
-            "networkRequestNetworkCapabilities";
+    public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST =
+            "networkRequestNetworkRequest";
 
 
     /**
      * Request a network to satisfy a set of {@link NetworkCapabilities}.
      *
-     * This function behavies identically to the callback-equiped version, but instead
-     * of {@link NetworkCallbackListener} a {@link PendingIntent} is used.  This means
+     * This function behavies identically to the version that takes a NetworkCallback, but instead
+     * of {@link NetworkCallback} a {@link PendingIntent} is used.  This means
      * the request may outlive the calling application and get called back when a suitable
      * network is found.
      * <p>
@@ -2291,10 +2286,10 @@
      * &lt;receiver&gt; tag in an AndroidManifest.xml file
      * <p>
      * The operation Intent is delivered with two extras, a {@link Network} typed
-     * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
-     * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES} containing
+     * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkRequest}
+     * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_REQUEST} containing
      * the original requests parameters.  It is important to create a new,
-     * {@link NetworkCallbackListener} based request before completing the processing of the
+     * {@link NetworkCallback} based request before completing the processing of the
      * Intent to reserve the network or it will be released shortly after the Intent
      * is processed.
      * <p>
@@ -2302,51 +2297,49 @@
      * two Intents defined by {@link Intent#filterEquals}), then it will be removed and
      * replaced by this one, effectively releasing the previous {@link NetworkRequest}.
      * <p>
-     * The request may be released normally by calling {@link #releaseNetworkRequest}.
+     * The request may be released normally by calling {@link #unregisterNetworkCallback}.
      *
-     * @param need {@link NetworkCapabilities} required by this request.
+     * @param request {@link NetworkRequest} describing this request.
      * @param operation Action to perform when the network is available (corresponds
-     *                  to the {@link NetworkCallbackListener#onAvailable} call.  Typically
+     *                  to the {@link NetworkCallback#onAvailable} call.  Typically
      *                  comes from {@link PendingIntent#getBroadcast}.
-     * @return A {@link NetworkRequest} object identifying the request.
+     * @hide
      */
-    public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
+    public void requestNetwork(NetworkRequest request, PendingIntent operation) {
         try {
-            return mService.pendingRequestForNetwork(need, operation);
+            mService.pendingRequestForNetwork(request.networkCapabilities, operation);
         } catch (RemoteException e) {}
-        return null;
     }
 
     /**
      * Registers to receive notifications about all networks which satisfy the given
-     * {@link NetworkCapabilities}.  The callbacks will continue to be called until
-     * either the application exits or the request is released using
-     * {@link #releaseNetworkRequest}.
+     * {@link NetworkRequest}.  The callbacks will continue to be called until
+     * either the application exits or {@link #unregisterNetworkCallback} is called
      *
-     * @param need {@link NetworkCapabilities} required by this request.
-     * @param networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable
-     *                         networks change state.
-     * @return A {@link NetworkRequest} object identifying the request.
+     * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+     *                        networks change state.
      */
-    public NetworkRequest listenForNetwork(NetworkCapabilities need,
-            NetworkCallbackListener networkCallbackListener) {
-        return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE);
+    public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
+        sendRequestForNetwork(request.networkCapabilities, networkCallback, 0, LISTEN, TYPE_NONE);
     }
 
     /**
-     * Releases a {@link NetworkRequest} generated either through a {@link #requestNetwork}
-     * or a {@link #listenForNetwork} call.  The {@link NetworkCallbackListener} given in the
-     * earlier call may continue receiving calls until the
-     * {@link NetworkCallbackListener#onReleased} function is called, signifying the end
-     * of the request.
+     * Unregisters callbacks about and possibly releases networks originating from
+     * {@link #requestNetwork} and {@link #registerNetworkCallback} calls.  If the
+     * given {@code NetworkCallback} had previosuly been used with {@code #requestNetwork},
+     * any networks that had been connected to only to satisfy that request will be
+     * disconnected.
      *
-     * @param networkRequest The {@link NetworkRequest} generated by an earlier call to
-     *                       {@link #requestNetwork} or {@link #listenForNetwork}.
+     * @param networkCallback The {@link NetworkCallback} used when making the request.
      */
-    public void releaseNetworkRequest(NetworkRequest networkRequest) {
-        if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
+    public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+        if (networkCallback == null || networkCallback.networkRequest == null ||
+                networkCallback.networkRequest.requestId == REQUEST_ID_UNSET) {
+            throw new IllegalArgumentException("Invalid NetworkCallback");
+        }
         try {
-            mService.releaseNetworkRequest(networkRequest);
+            mService.releaseNetworkRequest(networkCallback.networkRequest);
         } catch (RemoteException e) {}
     }
 
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index dd9c39f..b7af374 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.net.LinkAddress;
+import android.net.RouteInfo;
 
 /**
  * Callback class for receiving events from an INetworkManagementService
@@ -98,4 +99,14 @@
      * @param servers The IP addresses of the DNS servers.
      */
     void interfaceDnsServerInfo(String iface, long lifetime, in String[] servers);
+
+    /**
+     * A route has been added or updated.
+     */
+    void routeUpdated(in RouteInfo route);
+
+    /**
+     * A route has been removed.
+     */
+    void routeRemoved(in RouteInfo route);
 }
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index dfe0384..f1fa3eb 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Pair;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -42,13 +43,22 @@
  *
  * Objects of this class are immutable.
  */
-public class IpPrefix implements Parcelable {
+public final class IpPrefix implements Parcelable {
     private final byte[] address;  // network byte order
     private final int prefixLength;
 
+    private void checkAndMaskAddressAndPrefixLength() {
+        if (address.length != 4 && address.length != 16) {
+            throw new IllegalArgumentException(
+                    "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
+        }
+        NetworkUtils.maskRawAddress(address, prefixLength);
+    }
+
     /**
      * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
-     * network byte order and a prefix length.
+     * network byte order and a prefix length. Silently truncates the address to the prefix length,
+     * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}.
      *
      * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long.
      * @param prefixLength the prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
@@ -56,24 +66,46 @@
      * @hide
      */
     public IpPrefix(byte[] address, int prefixLength) {
-        if (address.length != 4 && address.length != 16) {
-            throw new IllegalArgumentException(
-                    "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
-        }
-        if (prefixLength < 0 || prefixLength > (address.length * 8)) {
-            throw new IllegalArgumentException("IpPrefix with " + address.length +
-                    " bytes has invalid prefix length " + prefixLength);
-        }
         this.address = address.clone();
         this.prefixLength = prefixLength;
-        // TODO: Validate that the non-prefix bits are zero
+        checkAndMaskAddressAndPrefixLength();
     }
 
     /**
+     * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently
+     * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently
+     * converted to {@code 192.0.2.0/24}.
+     *
+     * @param address the IP address. Must be non-null.
+     * @param prefixLength the prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
      * @hide
      */
     public IpPrefix(InetAddress address, int prefixLength) {
-        this(address.getAddress(), prefixLength);
+        // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
+        // which is unnecessary because getAddress() already returns a clone.
+        this.address = address.getAddress();
+        this.prefixLength = prefixLength;
+        checkAndMaskAddressAndPrefixLength();
+    }
+
+    /**
+     * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64".
+     * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24}
+     * is silently converted to {@code 192.0.2.0/24}.
+     *
+     * @param prefix the prefix to parse
+     *
+     * @hide
+     */
+    public IpPrefix(String prefix) {
+        // We don't reuse the (InetAddress, int) constructor because "error: call to this must be
+        // first statement in constructor". We could factor out setting the member variables to an
+        // init() method, but if we did, then we'd have to make the members non-final, or "error:
+        // cannot assign a value to final variable address". So we just duplicate the code here.
+        Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix);
+        this.address = ipAndMask.first.getAddress();
+        this.prefixLength = ipAndMask.second;
+        checkAndMaskAddressAndPrefixLength();
     }
 
     /**
@@ -129,7 +161,7 @@
     }
 
     /**
-     * Returns the prefix length of this {@code IpAddress}.
+     * Returns the prefix length of this {@code IpPrefix}.
      *
      * @return the prefix length.
      */
@@ -138,8 +170,21 @@
     }
 
     /**
+     * Returns a string representation of this {@code IpPrefix}.
+     *
+     * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::"}.
+     */
+    public String toString() {
+        try {
+            return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength;
+        } catch(UnknownHostException e) {
+            // Cosmic rays?
+            throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e);
+        }
+    }
+
+    /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public int describeContents() {
         return 0;
@@ -147,7 +192,6 @@
 
     /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByteArray(address);
@@ -156,7 +200,6 @@
 
     /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public static final Creator<IpPrefix> CREATOR =
             new Creator<IpPrefix>() {
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 5246078..f9a25f9 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Pair;
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
@@ -166,23 +167,9 @@
      * @hide
      */
     public LinkAddress(String address, int flags, int scope) {
-        InetAddress inetAddress = null;
-        int prefixLength = -1;
-        try {
-            String [] pieces = address.split("/", 2);
-            prefixLength = Integer.parseInt(pieces[1]);
-            inetAddress = InetAddress.parseNumericAddress(pieces[0]);
-        } catch (NullPointerException e) {            // Null string.
-        } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
-        } catch (NumberFormatException e) {           // Non-numeric prefix.
-        } catch (IllegalArgumentException e) {        // Invalid IP address.
-        }
-
-        if (inetAddress == null || prefixLength == -1) {
-            throw new IllegalArgumentException("Bad LinkAddress params " + address);
-        }
-
-        init(inetAddress, prefixLength, flags, scope);
+        // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
+        Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
+        init(ipAndMask.first, ipAndMask.second, flags, scope);
     }
 
     /**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index bb05936..e7184ed 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -31,6 +31,7 @@
 import java.util.Collections;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Describes the properties of a network link.
@@ -44,7 +45,7 @@
  * does not affect live networks.
  *
  */
-public class LinkProperties implements Parcelable {
+public final class LinkProperties implements Parcelable {
     // The interface described by the network link.
     private String mIfaceName;
     private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
@@ -334,15 +335,17 @@
     }
 
     /**
-     * Adds a {@link RouteInfo} to this {@code LinkProperties}.  If the {@link RouteInfo}
-     * had an interface name set and that differs from the interface set for this
-     * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.  The
-     * proper course is to add either un-named or properly named {@link RouteInfo}.
+     * Adds a {@link RouteInfo} to this {@code LinkProperties}, if not present. If the
+     * {@link RouteInfo} had an interface name set and that differs from the interface set for this
+     * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.  The proper
+     * course is to add either un-named or properly named {@link RouteInfo}.
      *
      * @param route A {@link RouteInfo} to add to this object.
+     * @return {@code false} if the route was already present, {@code true} if it was added.
+     *
      * @hide
      */
-    public void addRoute(RouteInfo route) {
+    public boolean addRoute(RouteInfo route) {
         if (route != null) {
             String routeIface = route.getInterface();
             if (routeIface != null && !routeIface.equals(mIfaceName)) {
@@ -350,8 +353,28 @@
                    "Route added with non-matching interface: " + routeIface +
                    " vs. " + mIfaceName);
             }
-            mRoutes.add(routeWithInterface(route));
+            route = routeWithInterface(route);
+            if (!mRoutes.contains(route)) {
+                mRoutes.add(route);
+                return true;
+            }
         }
+        return false;
+    }
+
+    /**
+     * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
+     * specify an interface and the interface must match the interface of this
+     * {@code LinkProperties}, or it will not be removed.
+     *
+     * @return {@code true} if the route was removed, {@code false} if it was not present.
+     *
+     * @hide
+     */
+    public boolean removeRoute(RouteInfo route) {
+        return route != null &&
+                Objects.equals(mIfaceName, route.getInterface()) &&
+                mRoutes.remove(route);
     }
 
     /**
@@ -463,7 +486,6 @@
 
     /**
      * Implement the Parcelable interface
-     * @hide
      */
     public int describeContents() {
         return 0;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index d933f26..318aabe 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -29,8 +29,9 @@
 
 /**
  * Identifies a {@code Network}.  This is supplied to applications via
- * {@link ConnectivityManager.NetworkCallbackListener} in response to
- * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}.
+ * {@link ConnectivityManager.NetworkCallback} in response to the active
+ * {@link ConnectivityManager#requestNetwork} or passive
+ * {@link ConnectivityManager#registerNetworkCallback} calls.
  * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
  * through a targeted {@link SocketFactory} or process-wide via
  * {@link ConnectivityManager#setProcessDefaultNetwork}.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 35274f1..fe96287 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -44,6 +44,9 @@
     private static final String TAG = "NetworkCapabilities";
     private static final boolean DBG = false;
 
+    /**
+     * @hide
+     */
     public NetworkCapabilities() {
     }
 
@@ -154,58 +157,64 @@
      * Multiple capabilities may be applied sequentially.  Note that when searching
      * for a network to satisfy a request, all capabilities requested must be satisfied.
      *
-     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+     * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+     * @return This NetworkCapability to facilitate chaining.
+     * @hide
      */
-    public void addNetworkCapability(int networkCapability) {
-        if (networkCapability < MIN_NET_CAPABILITY ||
-                networkCapability > MAX_NET_CAPABILITY) {
+    public NetworkCapabilities addCapability(int capability) {
+        if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
             throw new IllegalArgumentException("NetworkCapability out of range");
         }
-        mNetworkCapabilities |= 1 << networkCapability;
+        mNetworkCapabilities |= 1 << capability;
+        return this;
     }
 
     /**
      * Removes (if found) the given capability from this {@code NetworkCapability} instance.
      *
-     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+     * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+     * @return This NetworkCapability to facilitate chaining.
+     * @hide
      */
-    public void removeNetworkCapability(int networkCapability) {
-        if (networkCapability < MIN_NET_CAPABILITY ||
-                networkCapability > MAX_NET_CAPABILITY) {
+    public NetworkCapabilities removeCapability(int capability) {
+        if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
             throw new IllegalArgumentException("NetworkCapability out of range");
         }
-        mNetworkCapabilities &= ~(1 << networkCapability);
+        mNetworkCapabilities &= ~(1 << capability);
+        return this;
     }
 
     /**
      * Gets all the capabilities set on this {@code NetworkCapability} instance.
      *
-     * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values
+     * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values
      *         for this instance.
+     * @hide
      */
-    public Collection<Integer> getNetworkCapabilities() {
+    public int[] getCapabilities() {
         return enumerateBits(mNetworkCapabilities);
     }
 
     /**
      * Tests for the presence of a capabilitity on this instance.
      *
-     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
+     * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
      * @return {@code true} if set on this instance.
      */
-    public boolean hasCapability(int networkCapability) {
-        if (networkCapability < MIN_NET_CAPABILITY ||
-                networkCapability > MAX_NET_CAPABILITY) {
+    public boolean hasCapability(int capability) {
+        if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
             return false;
         }
-        return ((mNetworkCapabilities & (1 << networkCapability)) != 0);
+        return ((mNetworkCapabilities & (1 << capability)) != 0);
     }
 
-    private Collection<Integer> enumerateBits(long val) {
-        ArrayList<Integer> result = new ArrayList<Integer>();
+    private int[] enumerateBits(long val) {
+        int size = Long.bitCount(val);
+        int[] result = new int[size];
+        int index = 0;
         int resource = 0;
         while (val > 0) {
-            if ((val & 1) == 1) result.add(resource);
+            if ((val & 1) == 1) result[index++] = resource;
             val = val >> 1;
             resource++;
         }
@@ -265,33 +274,40 @@
      * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
      *
      * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
+     * @return This NetworkCapability to facilitate chaining.
+     * @hide
      */
-    public void addTransportType(int transportType) {
+    public NetworkCapabilities addTransportType(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             throw new IllegalArgumentException("TransportType out of range");
         }
         mTransportTypes |= 1 << transportType;
+        return this;
     }
 
     /**
      * Removes (if found) the given transport from this {@code NetworkCapability} instance.
      *
      * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
+     * @return This NetworkCapability to facilitate chaining.
+     * @hide
      */
-    public void removeTransportType(int transportType) {
+    public NetworkCapabilities removeTransportType(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             throw new IllegalArgumentException("TransportType out of range");
         }
         mTransportTypes &= ~(1 << transportType);
+        return this;
     }
 
     /**
      * Gets all the transports set on this {@code NetworkCapability} instance.
      *
-     * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values
+     * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values
      *         for this instance.
+     * @hide
      */
-    public Collection<Integer> getTransportTypes() {
+    public int[] getTransportTypes() {
         return enumerateBits(mTransportTypes);
     }
 
@@ -340,6 +356,7 @@
      * fast backhauls and slow backhauls.
      *
      * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+     * @hide
      */
     public void setLinkUpstreamBandwidthKbps(int upKbps) {
         mLinkUpBandwidthKbps = upKbps;
@@ -368,6 +385,7 @@
      * fast backhauls and slow backhauls.
      *
      * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+     * @hide
      */
     public void setLinkDownstreamBandwidthKbps(int downKbps) {
         mLinkDownBandwidthKbps = downKbps;
@@ -464,24 +482,22 @@
         };
 
     public String toString() {
-        Collection<Integer> types = getTransportTypes();
-        String transports = (types.size() > 0 ? " Transports: " : "");
-        Iterator<Integer> i = types.iterator();
-        while (i.hasNext()) {
-            switch (i.next()) {
+        int[] types = getTransportTypes();
+        String transports = (types.length > 0 ? " Transports: " : "");
+        for (int i = 0; i < types.length;) {
+            switch (types[i]) {
                 case TRANSPORT_CELLULAR:    transports += "CELLULAR"; break;
                 case TRANSPORT_WIFI:        transports += "WIFI"; break;
                 case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
                 case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
             }
-            if (i.hasNext()) transports += "|";
+            if (++i < types.length) transports += "|";
         }
 
-        types = getNetworkCapabilities();
-        String capabilities = (types.size() > 0 ? " Capabilities: " : "");
-        i = types.iterator();
-        while (i.hasNext()) {
-            switch (i.next().intValue()) {
+        types = getCapabilities();
+        String capabilities = (types.length > 0 ? " Capabilities: " : "");
+        for (int i = 0; i < types.length; ) {
+            switch (types[i]) {
                 case NET_CAPABILITY_MMS:            capabilities += "MMS"; break;
                 case NET_CAPABILITY_SUPL:           capabilities += "SUPL"; break;
                 case NET_CAPABILITY_DUN:            capabilities += "DUN"; break;
@@ -497,7 +513,7 @@
                 case NET_CAPABILITY_INTERNET:       capabilities += "INTERNET"; break;
                 case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
             }
-            if (i.hasNext()) capabilities += "&";
+            if (++i < types.length) capabilities += "&";
         }
 
         String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 47377e9..36dc573 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -22,19 +22,14 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork}
- * or {@link ConnectivityManager#listenForNetwork}.
- *
- * This token records the {@link NetworkCapabilities} used to make the request and identifies
- * the request.  It should be used to release the request via
- * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired.
+ * Defines a request for a network, made through {@link NetworkRequest.Builder} and used
+ * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
+ * via {@link ConnectivityManager#registerNetworkCallback}.
  */
 public class NetworkRequest implements Parcelable {
     /**
-     * The {@link NetworkCapabilities} that define this request.  This should not be modified.
-     * The networkCapabilities of the request are set when
-     * {@link ConnectivityManager#requestNetwork} is called and the value is presented here
-     * as a convenient reminder of what was requested.
+     * The {@link NetworkCapabilities} that define this request.
+     * @hide
      */
     public final NetworkCapabilities networkCapabilities;
 
@@ -71,6 +66,95 @@
         this.legacyType = that.legacyType;
     }
 
+    /**
+     * Builder used to create {@link NetworkRequest} objects.  Specify the Network features
+     * needed in terms of {@link NetworkCapabilities} features
+     */
+    public static class Builder {
+        private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities();
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {}
+
+        /**
+         * Build {@link NetworkRequest} give the current set of capabilities.
+         */
+        public NetworkRequest build() {
+            return new NetworkRequest(mNetworkCapabilities, ConnectivityManager.TYPE_NONE,
+                    ConnectivityManager.REQUEST_ID_UNSET);
+        }
+
+        /**
+         * Add the given capability requirement to this builder.  These represent
+         * the requested network's required capabilities.  Note that when searching
+         * for a network to satisfy a request, all capabilities requested must be
+         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*}
+         * definitions.
+         *
+         * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
+         * @return The builder to facilitate chaining
+         *         {@code builder.addCapability(...).addCapability();}.
+         */
+        public Builder addCapability(int capability) {
+            mNetworkCapabilities.addCapability(capability);
+            return this;
+        }
+
+        /**
+         * Removes (if found) the given capability from this builder instance.
+         *
+         * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to remove.
+         * @return The builder to facilitate chaining.
+         */
+        public Builder removeCapability(int capability) {
+            mNetworkCapabilities.removeCapability(capability);
+            return this;
+        }
+
+        /**
+         * Adds the given transport requirement to this builder.  These represent
+         * the set of allowed transports for the request.  Only networks using one
+         * of these transports will satisfy the request.  If no particular transports
+         * are required, none should be specified here.  See {@link NetworkCapabilities}
+         * for {@code TRANSPORT_*} definitions.
+         *
+         * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to add.
+         * @return The builder to facilitate chaining.
+         */
+        public Builder addTransportType(int transportType) {
+            mNetworkCapabilities.addTransportType(transportType);
+            return this;
+        }
+
+        /**
+         * Removes (if found) the given transport from this builder instance.
+         *
+         * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to remove.
+         * @return The builder to facilitate chaining.
+         */
+        public Builder removeTransportType(int transportType) {
+            mNetworkCapabilities.removeTransportType(transportType);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setLinkUpstreamBandwidthKbps(int upKbps) {
+            mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps);
+            return this;
+        }
+        /**
+         * @hide
+         */
+        public Builder setLinkDownstreamBandwidthKbps(int downKbps) {
+            mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps);
+            return this;
+        }
+    }
+
     // implement the Parcelable interface
     public int describeContents() {
         return 0;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b02f88e..15c0a71 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -24,6 +24,8 @@
 import java.util.Locale;
 
 import android.util.Log;
+import android.util.Pair;
+
 
 /**
  * Native methods for managing network interfaces.
@@ -218,24 +220,17 @@
     }
 
     /**
-     * Get InetAddress masked with prefixLength.  Will never return null.
-     * @param IP address which will be masked with specified prefixLength
-     * @param prefixLength the prefixLength used to mask the IP
+     *  Masks a raw IP address byte array with the specified prefix length.
      */
-    public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
-        if (address == null) {
-            throw new RuntimeException("getNetworkPart doesn't accept null address");
-        }
-
-        byte[] array = address.getAddress();
-
+    public static void maskRawAddress(byte[] array, int prefixLength) {
         if (prefixLength < 0 || prefixLength > array.length * 8) {
-            throw new RuntimeException("getNetworkPart - bad prefixLength");
+            throw new RuntimeException("IP address with " + array.length +
+                    " bytes has invalid prefix length " + prefixLength);
         }
 
         int offset = prefixLength / 8;
-        int reminder = prefixLength % 8;
-        byte mask = (byte)(0xFF << (8 - reminder));
+        int remainder = prefixLength % 8;
+        byte mask = (byte)(0xFF << (8 - remainder));
 
         if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
 
@@ -244,6 +239,16 @@
         for (; offset < array.length; offset++) {
             array[offset] = 0;
         }
+    }
+
+    /**
+     * Get InetAddress masked with prefixLength.  Will never return null.
+     * @param address the IP address to mask with
+     * @param prefixLength the prefixLength used to mask the IP
+     */
+    public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
+        byte[] array = address.getAddress();
+        maskRawAddress(array, prefixLength);
 
         InetAddress netPart = null;
         try {
@@ -255,6 +260,30 @@
     }
 
     /**
+     * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
+     * @hide
+     */
+    public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
+        InetAddress address = null;
+        int prefixLength = -1;
+        try {
+            String[] pieces = ipAndMaskString.split("/", 2);
+            prefixLength = Integer.parseInt(pieces[1]);
+            address = InetAddress.parseNumericAddress(pieces[0]);
+        } catch (NullPointerException e) {            // Null string.
+        } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
+        } catch (NumberFormatException e) {           // Non-numeric prefix.
+        } catch (IllegalArgumentException e) {        // Invalid IP address.
+        }
+
+        if (address == null || prefixLength == -1) {
+            throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
+        }
+
+        return new Pair<InetAddress, Integer>(address, prefixLength);
+    }
+
+    /**
      * Check if IP address type is consistent between two InetAddress.
      * @return true if both are the same type.  False otherwise.
      */
diff --git a/core/java/android/net/PSKKeyManager.java b/core/java/android/net/PSKKeyManager.java
new file mode 100644
index 0000000..92dd141
--- /dev/null
+++ b/core/java/android/net/PSKKeyManager.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import java.net.Socket;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Provider of key material for pre-shared key (PSK) key exchange used in TLS-PSK cipher suites.
+ *
+ * <h3>Overview of TLS-PSK</h3>
+ *
+ * <p>TLS-PSK is a set of TLS/SSL cipher suites which rely on a symmetric pre-shared key (PSK) to
+ * secure the TLS/SSL connection and mutually authenticate its peers. These cipher suites may be
+ * a more natural fit compared to conventional public key based cipher suites in some scenarios
+ * where communication between peers is bootstrapped via a separate step (for example, a pairing
+ * step) and requires both peers to authenticate each other. In such scenarios a symmetric key (PSK)
+ * can be exchanged during the bootstrapping step, removing the need to generate and exchange public
+ * key pairs and X.509 certificates.</p>
+ *
+ * <p>When a TLS-PSK cipher suite is used, both peers have to use the same key for the TLS/SSL
+ * handshake to succeed. Thus, both peers are implicitly authenticated by a successful handshake.
+ * This removes the need to use a {@code TrustManager} in conjunction with this {@code KeyManager}.
+ * </p>
+ *
+ * <h3>Supporting multiple keys</h3>
+ *
+ * <p>A peer may have multiple keys to choose from. To help choose the right key, during the handshake
+ * the server can provide a <em>PSK identity hint</em> to the client, and the client can provide a
+ * <em>PSK identity</em> to the server. The contents of these two pieces of information are specific
+ * to application-level protocols.</p>
+ *
+ * <p><em>NOTE: Both the PSK identity hint and the PSK identity are transmitted in cleartext.
+ * Moreover, these data are received and processed prior to peer having been authenticated. Thus,
+ * they must not contain or leak key material or other sensitive information, and should be
+ * treated (e.g., parsed) with caution, as untrusted data.</em></p>
+ *
+ * <p>The high-level flow leading to peers choosing a key during TLS/SSL handshake is as follows:
+ * <ol>
+ * <li>Server receives a handshake request from client.
+ * <li>Server replies, optionally providing a PSK identity hint to client.</li>
+ * <li>Client chooses the key.</li>
+ * <li>Client provides a PSK identity of the chosen key to server.</li>
+ * <li>Server chooses the key.</li>
+ * </ol></p>
+ *
+ * <p>In the flow above, either peer can signal that they do not have a suitable key, in which case
+ * the the handshake will be aborted immediately. This may enable a network attacker who does not
+ * know the key to learn which PSK identity hints or PSK identities are supported. If this is a
+ * concern then a randomly generated key should be used in the scenario where no key is available.
+ * This will lead to the handshake aborting later, due to key mismatch -- same as in the scenario
+ * where a key is available -- making it appear to the attacker that all PSK identity hints and PSK
+ * identities are supported.</p>
+ *
+ * <h3>Maximum sizes</h3>
+ *
+ * <p>The maximum supported sizes are as follows:
+ * <ul>
+ * <li>256 bytes for keys (see {@link #MAX_KEY_LENGTH_BYTES}),</li>
+ * <li>128 bytes for PSK identity and PSK identity hint (in modified UTF-8 representation) (see
+ * {@link #MAX_IDENTITY_LENGTH_BYTES} and {@link #MAX_IDENTITY_HINT_LENGTH_BYTES}).</li>
+ * </ul></p>
+ *
+ * <h3>Example</h3>
+ * The following example illustrates how to create an {@code SSLContext} which enables the use of
+ * TLS-PSK in {@code SSLSocket}, {@code SSLServerSocket} and {@code SSLEngine} instances obtained
+ * from it.
+ * <pre> {@code
+ *  PSKKeyManager myPskKeyManager = ...;
+ *
+ * SSLContext sslContext = SSLContext.getInstance("TLS");
+ * sslContext.init(
+ *         new KeyManager[] &#123;myPskKeyManager&#125;,
+ *         new TrustManager[0], // No TrustManagers needed in TLS-PSK
+ *         null // Use the default source of entropy
+ *         );
+ *
+ * SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(...);
+ * // Enable a TLS-PSK cipher suite (no TLS-PSK cipher suites are enabled by default)
+ * sslSocket.setEnabledCipherSuites(new String[] &#123;"TLS_PSK_WITH_AES_128_CBC_SHA"&#125;);
+ * sslSocket.startHandshake();
+ * }</pre>
+ */
+public interface PSKKeyManager extends com.android.org.conscrypt.PSKKeyManager {
+    // IMPLEMENTATION DETAILS: This class exists only because the default implemenetation of the
+    // TLS/SSL JSSE provider (currently Conscrypt) cannot depend on Android framework classes.
+    // As a result, this framework class simply extends the PSKKeyManager interface from Conscrypt
+    // without adding any new methods or fields. Moreover, for technical reasons (Conscrypt classes
+    // are "hidden") this class replaces the Javadoc of Conscrypt's PSKKeyManager.
+
+    /**
+     * Maximum supported length (in bytes) for PSK identity hint (in modified UTF-8 representation).
+     */
+    int MAX_IDENTITY_HINT_LENGTH_BYTES =
+            com.android.org.conscrypt.PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES;
+
+    /** Maximum supported length (in bytes) for PSK identity (in modified UTF-8 representation). */
+    int MAX_IDENTITY_LENGTH_BYTES =
+            com.android.org.conscrypt.PSKKeyManager.MAX_IDENTITY_LENGTH_BYTES;
+
+    /** Maximum supported length (in bytes) for PSK. */
+    int MAX_KEY_LENGTH_BYTES = com.android.org.conscrypt.PSKKeyManager.MAX_KEY_LENGTH_BYTES;
+
+    /**
+     * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+     * socket.
+     *
+     * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+     */
+    @Override
+    String chooseServerKeyIdentityHint(Socket socket);
+
+    /**
+     * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+     * engine.
+     *
+     * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+     */
+    @Override
+    String chooseServerKeyIdentityHint(SSLEngine engine);
+
+    /**
+     * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+     * socket.
+     *
+     * @param identityHint identity hint provided by the server or {@code null} if none provided.
+     *
+     * @return PSK identity to provide to the server. {@code null} is permitted but will be
+     *         converted into an empty string.
+     */
+    @Override
+    String chooseClientKeyIdentity(String identityHint, Socket socket);
+
+    /**
+     * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+     * engine.
+     *
+     * @param identityHint identity hint provided by the server or {@code null} if none provided.
+     *
+     * @return PSK identity to provide to the server. {@code null} is permitted but will be
+     *         converted into an empty string.
+     */
+    @Override
+    String chooseClientKeyIdentity(String identityHint, SSLEngine engine);
+
+    /**
+     * Gets the PSK to use for the provided socket.
+     *
+     * @param identityHint identity hint provided by the server to help select the key or
+     *        {@code null} if none provided.
+     * @param identity identity provided by the client to help select the key.
+     *
+     * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+     *         the handshake.
+     */
+    @Override
+    SecretKey getKey(String identityHint, String identity, Socket socket);
+
+    /**
+     * Gets the PSK to use for the provided engine.
+     *
+     * @param identityHint identity hint provided by the server to help select the key or
+     *        {@code null} if none provided.
+     * @param identity identity provided by the client to help select the key.
+     *
+     * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+     *         the handshake.
+     */
+    @Override
+    SecretKey getKey(String identityHint, String identity, SSLEngine engine);
+}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index af27e1d..63d6cd3 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -46,7 +46,7 @@
  * destination and gateway are both specified, they must be of the same address family
  * (IPv4 or IPv6).
  */
-public class RouteInfo implements Parcelable {
+public final class RouteInfo implements Parcelable {
     /**
      * The IP destination address for this route.
      * TODO: Make this an IpPrefix.
@@ -248,7 +248,7 @@
      * Retrieves the gateway or next hop {@link InetAddress} for this route.
      *
      * @return {@link InetAddress} specifying the gateway or next hop.  This may be
-     &                             {@code null} for a directly-connected route."
+     *                             {@code null} for a directly-connected route."
      */
     public InetAddress getGateway() {
         return mGateway;
@@ -361,7 +361,7 @@
 
         RouteInfo target = (RouteInfo) obj;
 
-        return Objects.equals(mDestination, target.getDestination()) &&
+        return Objects.equals(mDestination, target.getDestinationLinkAddress()) &&
                 Objects.equals(mGateway, target.getGateway()) &&
                 Objects.equals(mInterface, target.getInterface());
     }
@@ -378,7 +378,6 @@
 
     /**
      * Implement the Parcelable interface
-     * @hide
      */
     public int describeContents() {
         return 0;
@@ -386,7 +385,6 @@
 
     /**
      * Implement the Parcelable interface
-     * @hide
      */
     public void writeToParcel(Parcel dest, int flags) {
         if (mDestination == null) {
@@ -409,7 +407,6 @@
 
     /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public static final Creator<RouteInfo> CREATOR =
         new Creator<RouteInfo>() {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index cd47099..e77ef95 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -39,9 +39,6 @@
     UserInfo getProfileParent(int userHandle);
     UserInfo getUserInfo(int userHandle);
     boolean isRestricted();
-    void setGuestEnabled(boolean enable);
-    boolean isGuestEnabled();
-    void wipeUser(int userHandle);
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 914c170..afbf983 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
 
 package android.os;
 
+import android.util.SparseArray;
+
 import java.io.PrintWriter;
+import java.util.HashMap;
 
 /**
  * Representation of a user on the device.
@@ -66,6 +69,8 @@
 
     final int mHandle;
 
+    private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
+
     /**
      * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
      * user.
@@ -124,6 +129,18 @@
         return getUserId(Binder.getCallingUid());
     }
 
+    /** @hide */
+    public static final UserHandle getCallingUserHandle() {
+        int userId = getUserId(Binder.getCallingUid());
+        UserHandle userHandle = userHandles.get(userId);
+        // Intentionally not synchronized to save time
+        if (userHandle == null) {
+            userHandle = new UserHandle(userId);
+            userHandles.put(userId, userHandle);
+        }
+        return userHandle;
+    }
+
     /**
      * Returns the uid that is composed from the userId and the appId.
      * @hide
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 91fbb9d..468cfe0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.R;
@@ -361,6 +362,16 @@
     }
 
     /**
+     * Checks if the calling app is running as a guest user.
+     * @return whether the caller is a guest user.
+     * @hide
+     */
+    public boolean isGuestUser() {
+        UserInfo user = getUserInfo(UserHandle.myUserId());
+        return user != null ? user.isGuest() : false;
+    }
+
+    /**
      * Return whether the given user is actively running.  This means that
      * the user is in the "started" state, not "stopped" -- it is currently
      * allowed to run code through scheduled alarms, receiving broadcasts,
@@ -550,6 +561,21 @@
     }
 
     /**
+     * Creates a guest user and configures it.
+     * @param context an application context
+     * @param name the name to set for the user
+     * @hide
+     */
+    public UserInfo createGuest(Context context, String name) {
+        UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);
+        if (guest != null) {
+            Settings.Secure.putStringForUser(context.getContentResolver(),
+                    Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+        }
+        return guest;
+    }
+
+    /**
      * Creates a user with the specified name and options as a profile of another user.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
@@ -827,50 +853,6 @@
     }
 
     /**
-     * Enable or disable the use of a guest account. If disabled, the existing guest account
-     * will be wiped.
-     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * @param enable whether to enable a guest account.
-     * @hide
-     */
-    public void setGuestEnabled(boolean enable) {
-        try {
-            mService.setGuestEnabled(enable);
-        } catch (RemoteException re) {
-            Log.w(TAG, "Could not change guest account availability to " + enable);
-        }
-    }
-
-    /**
-     * Checks if a guest user is enabled for this device.
-     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * @return whether a guest user is enabled
-     * @hide
-     */
-    public boolean isGuestEnabled() {
-        try {
-            return mService.isGuestEnabled();
-        } catch (RemoteException re) {
-            Log.w(TAG, "Could not retrieve guest enabled state");
-            return false;
-        }
-    }
-
-    /**
-     * Wipes all the data for a user, but doesn't remove the user.
-     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * @param userHandle
-     * @hide
-     */
-    public void wipeUser(int userHandle) {
-        try {
-            mService.wipeUser(userHandle);
-        } catch (RemoteException re) {
-            Log.w(TAG, "Could not wipe user " + userHandle);
-        }
-    }
-
-    /**
      * Returns the maximum number of users that can be created on this device. A return value
      * of 1 means that it is a single user device.
      * @hide
@@ -900,7 +882,9 @@
                 ++switchableUserCount;
             }
         }
-        return switchableUserCount > 1;
+        final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.GUEST_USER_ENABLED, 0) == 1;
+        return switchableUserCount > 1 || guestEnabled;
     }
 
     /**
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index e32890d..67f6409 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -40,11 +40,19 @@
             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
-        final TypedArray a = context.obtainStyledAttributes(
+        TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes);
         setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
         a.recycle();
-        setLayoutResource(com.android.internal.R.layout.preference_widget_seekbar);
+
+        a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.SeekBarPreference, defStyleAttr, defStyleRes);
+        final int layoutResId = a.getResourceId(
+                com.android.internal.R.styleable.SeekBarPreference_layout,
+                com.android.internal.R.layout.preference_widget_seekbar);
+        a.recycle();
+
+        setLayoutResource(layoutResId);
     }
 
     public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -52,7 +60,7 @@
     }
 
     public SeekBarPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle);
     }
 
     public SeekBarPreference(Context context) {
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index fa85903..3853003 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -156,8 +156,8 @@
      *  @param title    Title for the bookmark. Can be null or empty string.
      *  @param url      Url for the bookmark. Can be null or empty string.
      */
-    public static final void saveBookmark(Context c, 
-                                          String title, 
+    public static final void saveBookmark(Context c,
+                                          String title,
                                           String url) {
         Intent i = new Intent(Intent.ACTION_INSERT, Browser.BOOKMARKS_URI);
         i.putExtra("title", title);
@@ -234,10 +234,10 @@
      *
      *  @param cr   The ContentResolver used to access the database.
      */
-    public static final Cursor getAllBookmarks(ContentResolver cr) throws 
+    public static final Cursor getAllBookmarks(ContentResolver cr) throws
             IllegalStateException {
         return cr.query(Bookmarks.CONTENT_URI,
-                new String[] { Bookmarks.URL }, 
+                new String[] { Bookmarks.URL },
                 Bookmarks.IS_FOLDER + " = 0", null, null);
     }
 
@@ -398,24 +398,17 @@
         // TODO make a single request to the provider to do this in a single transaction
         Cursor cursor = null;
         try {
-            
+
             // Select non-bookmark history, ordered by date
             cursor = cr.query(History.CONTENT_URI,
                     new String[] { History._ID, History.URL, History.DATE_LAST_VISITED },
                     null, null, History.DATE_LAST_VISITED + " ASC");
 
             if (cursor.moveToFirst() && cursor.getCount() >= MAX_HISTORY_COUNT) {
-                WebIconDatabase iconDb = null;
-                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {                  
-                    iconDb = WebIconDatabase.getInstance();
-                }
                 /* eliminate oldest history items */
                 for (int i = 0; i < TRUNCATE_N_OLDEST; i++) {
                     cr.delete(ContentUris.withAppendedId(History.CONTENT_URI, cursor.getLong(0)),
                         null, null);
-                    if (iconDb != null) {
-                        iconDb.releaseIconForPageUrl(cursor.getString(1));
-                    }
                     if (!cursor.moveToNext()) break;
                 }
             }
@@ -475,18 +468,6 @@
             cursor = cr.query(History.CONTENT_URI, new String[] { History.URL }, whereClause,
                     null, null);
             if (cursor.moveToFirst()) {
-                WebIconDatabase iconDb = null;
-                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
-                    iconDb = WebIconDatabase.getInstance();
-                }
-                do {
-                  // Delete favicons
-                  // TODO don't release if the URL is bookmarked
-                  if (iconDb != null) {                    
-                      iconDb.releaseIconForPageUrl(cursor.getString(0));
-                  }
-                } while (cursor.moveToNext());
-
                 cr.delete(History.CONTENT_URI, whereClause, null);
             }
         } catch (IllegalStateException e) {
@@ -531,7 +512,7 @@
      * @param cr    The ContentResolver used to access the database.
      * @param url   url to remove.
      */
-    public static final void deleteFromHistory(ContentResolver cr, 
+    public static final void deleteFromHistory(ContentResolver cr,
                                                String url) {
         cr.delete(History.CONTENT_URI, History.URL + "=?", new String[] { url });
     }
@@ -565,7 +546,7 @@
             Log.e(LOGTAG, "clearSearches", e);
         }
     }
-    
+
     /**
      *  Request all icons from the database.  This call must either be called
      *  in the main thread or have had Looper.prepare() invoked in the calling
@@ -574,14 +555,12 @@
      *  @param  cr The ContentResolver used to access the database.
      *  @param  where Clause to be used to limit the query from the database.
      *          Must be an allowable string to be passed into a database query.
-     *  @param  listener IconListener that gets the icons once they are 
+     *  @param  listener IconListener that gets the icons once they are
      *          retrieved.
      */
     public static final void requestAllIcons(ContentResolver cr, String where,
             WebIconDatabase.IconListener listener) {
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
-            WebIconDatabase.getInstance().bulkRequestIconForPageUrl(cr, where, listener);
-        }
+        // Do nothing: this is no longer used.
     }
 
     /**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index ba66e65..1e7d7f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -7963,8 +7963,7 @@
                 actualContext = ((ContextWrapper) actualContext).getBaseContext();
             }
             final int intentFlags = (actualContext instanceof Activity)
-                    ? Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
-                    : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
+                    ? 0 : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
 
             // Launch pivot dialog through intent for now
             final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bec401e..06c05ee 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -791,6 +791,15 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PAIRING_SETTINGS = "android.settings.PAIRING_SETTINGS";
 
+    /**
+     * Activity Action: Show battery saver settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_BATTERY_SAVER_SETTINGS
+            = "android.settings.BATTERY_SAVER_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -4528,6 +4537,12 @@
         public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
 
         /**
+         * Specifies the package name currently configured to be the primary phone application
+         * @hide
+         */
+        public static final String PHONE_DEFAULT_APPLICATION = "phone_default_application";
+
+        /**
          * Name of a package that the current user has explicitly allowed to see all of that
          * user's notifications.
          *
@@ -4567,6 +4582,16 @@
         public static final String DISPLAY_INTERCEPTED_NOTIFICATIONS = "display_intercepted_notifications";
 
         /**
+         * If enabled, apps should try to skip any introductory hints on first launch. This might
+         * apply to users that are already familiar with the environment or temporary users, like
+         * guests.
+         * <p>
+         * Type : int (0 to show hints, 1 to skip showing hints)
+         * @hide
+         */
+        public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -6024,6 +6049,13 @@
          */
         public static final String LOW_POWER_MODE = "low_power";
 
+        /**
+         * Battery level [1-99] at which low power mode automatically turns on.
+         * If 0, it will not automatically turn on.
+         * @hide
+         */
+        public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
+
          /**
          * If 1, the activity manager will aggressively finish activities and
          * processes as soon as they are no longer needed.  If 0, the normal
@@ -6200,6 +6232,14 @@
         public static final String DEVICE_NAME = "device_name";
 
         /**
+         * Whether it should be possible to create a guest user on the device.
+         * <p>
+         * Type: int (0 for disabled, 1 for enabled)
+         * @hide
+         */
+        public static final String GUEST_USER_ENABLED = "guest_user_enabled";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
@@ -6513,6 +6553,53 @@
         public static boolean putFloat(ContentResolver cr, String name, float value) {
             return putString(cr, name, Float.toString(value));
         }
+
+
+        /**
+          * Subscription to be used for voice call on a multi sim device. The supported values
+          * are 0 = SUB1, 1 = SUB2 and etc.
+          * @hide
+          */
+        public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call";
+
+        /**
+          * Used to provide option to user to select subscription during dial.
+          * The supported values are 0 = disable or 1 = enable prompt.
+          * @hide
+          */
+        public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt";
+
+        /**
+          * Subscription to be used for data call on a multi sim device. The supported values
+          * are 0 = SUB1, 1 = SUB2 and etc.
+          * @hide
+          */
+        public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call";
+
+        /**
+          * Subscription to be used for SMS on a multi sim device. The supported values
+          * are 0 = SUB1, 1 = SUB2 and etc.
+          * @hide
+          */
+        public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms";
+
+       /**
+          * Used to provide option to user to select subscription during send SMS.
+          * The value 1 - enable, 0 - disable
+          * @hide
+          */
+        public static final String MULTI_SIM_SMS_PROMPT = "multi_sim_sms_prompt";
+
+
+
+        /** User preferred subscriptions setting.
+          * This holds the details of the user selected subscription from the card and
+          * the activation status. Each settings string have the coma separated values
+          * iccId,appType,appId,activationStatus,3gppIndex,3gpp2Index
+          * @hide
+         */
+        public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1",
+                "user_preferred_sub2","user_preferred_sub3"};
     }
 
     /**
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 2fcec52..b6137d1 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -22,12 +22,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
+import android.util.Slog;
 
 /**
  * A class that coordinates access to the fingerprint hardware.
@@ -36,31 +38,40 @@
 public class FingerprintManager {
     private static final String TAG = "FingerprintManager";
     private static final boolean DEBUG = true;
-    private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
-    private static final String FINGERPRINT_SERVICE_CLASS =
-            "com.android.service.fingerprint.FingerprintService";
     private static final int MSG_ENROLL_RESULT = 100;
-    private static final int MSG_SCANNED = 101;
-    private static final int MSG_ERROR = 102;
-    private static final int MSG_REMOVED = 103;
+    private static final int MSG_ACQUIRED = 101;
+    private static final int MSG_PROCESSED = 102;
+    private static final int MSG_ERROR = 103;
+    private static final int MSG_REMOVED = 104;
 
+    // Errors generated by layers above HAL
     public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
-    public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
 
-    // Progress messages.
-    public static final int FINGERPRINT_SCANNED = 1;
-    public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+    // Message types.  Must agree with HAL (fingerprint.h)
+    public static final int FINGERPRINT_ERROR = -1;
+    public static final int FINGERPRINT_ACQUIRED = 1;
+    public static final int FINGERPRINT_PROCESSED = 2;
+    public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
     public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
 
-    // Error messages. Must agree with fingerprint HAL definitions.
+    // Error messages. Must agree with HAL (fingerprint.h)
     public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
-    public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+    public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
     public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
     public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
 
+    // FINGERPRINT_ACQUIRED messages.  Must agree with HAL (fingerprint.h)
+    public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+    public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
+    public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
+    public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
+    public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
+    public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
+
     private IFingerprintService mService;
     private FingerprintManagerReceiver mClientReceiver;
     private Context mContext;
+    private IBinder mToken = new Binder();
 
     private Handler mHandler = new Handler() {
         public void handleMessage(android.os.Message msg) {
@@ -69,8 +80,11 @@
                     case MSG_ENROLL_RESULT:
                         mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
                         break;
-                    case MSG_SCANNED:
-                        mClientReceiver.onScanned(msg.arg1, msg.arg2);
+                    case MSG_ACQUIRED:
+                        mClientReceiver.onAcquired(msg.arg1);
+                        break;
+                    case MSG_PROCESSED:
+                        mClientReceiver.onProcessed(msg.arg1);
                         break;
                     case MSG_ERROR:
                         mClientReceiver.onError(msg.arg1);
@@ -82,45 +96,26 @@
         }
     };
 
-    public FingerprintManager(Context context) {
+    public FingerprintManager(Context context, IFingerprintService service) {
         mContext = context;
-        // Connect to service...
-        Intent intent = new Intent();
-        intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
-        if (!context.bindServiceAsUser(intent, mFingerprintConnection,
-                Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
-            if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+        mService = service;
+        if (mService == null) {
+            Slog.v(TAG, "FingerprintManagerService was null");
         }
     }
 
-    private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
-            mService = IFingerprintService.Stub.asInterface(service);
-            try {
-                mService.startListening(mServiceReceiver, getCurrentUserId());
-            } catch (RemoteException e) {
-                if (DEBUG) Log.v(TAG, "Failed to set callback", e);
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
-            mService = null;
-        }
-    };
-
     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
 
         public void onEnrollResult(int fingerprintId,  int remaining) {
             mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
         }
 
-        public void onScanned(int fingerprintId, int confidence) {
-            mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
-                    .sendToTarget();;
+        public void onAcquired(int acquireInfo) {
+            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
+        }
+
+        public void onProcessed(int fingerprintId) {
+            mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
         }
 
         public void onError(int error) {
@@ -151,12 +146,14 @@
      */
     public void enroll(long timeout) {
         if (mServiceReceiver == null) {
-            throw new IllegalStateException("enroll: Call registerCallback() first");
+            sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+            return;
         }
         if (mService != null) try {
-            mService.enroll(timeout, getCurrentUserId());
+            mService.enroll(mToken, timeout, getCurrentUserId());
         } catch (RemoteException e) {
             Log.v(TAG, "Remote exception while enrolling: ", e);
+            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
         }
     }
 
@@ -166,10 +163,19 @@
      * @param fingerprintId
      */
     public void remove(int fingerprintId) {
-        if (mService != null) try {
-            mService.remove(fingerprintId, getCurrentUserId());
-        } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+        if (mServiceReceiver == null) {
+            sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+            return;
+        }
+        if (mService != null) {
+            try {
+                mService.remove(mToken, fingerprintId, getCurrentUserId());
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+            }
+        } else {
+            Log.w(TAG, "remove(): Service not connected!");
+            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
         }
     }
 
@@ -181,10 +187,13 @@
         mClientReceiver = receiver;
         if (mService != null) {
             try {
-                mService.startListening(mServiceReceiver, getCurrentUserId());
+                mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
             } catch (RemoteException e) {
                 Log.v(TAG, "Remote exception in startListening(): ", e);
             }
+        } else {
+            Log.w(TAG, "startListening(): Service not connected!");
+            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
         }
     }
 
@@ -201,15 +210,38 @@
      * Stops the client from listening to fingerprint events.
      */
     public void stopListening() {
-        mClientReceiver = null;
         if (mService != null) {
             try {
-                mService.stopListening(getCurrentUserId());
+                mService.stopListening(mToken, getCurrentUserId());
+                mClientReceiver = null;
             } catch (RemoteException e) {
                 Log.v(TAG, "Remote exception in stopListening(): ", e);
             }
         } else {
             Log.w(TAG, "stopListening(): Service not connected!");
+            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
         }
     }
+
+    public void enrollCancel() {
+        if (mServiceReceiver == null) {
+            sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+            return;
+        }
+        if (mService != null) {
+            try {
+                mService.enrollCancel(mToken, getCurrentUserId());
+                mClientReceiver = null;
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in enrollCancel(): ", e);
+                sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+            }
+        } else {
+            Log.w(TAG, "enrollCancel(): Service not connected!");
+        }
+    }
+
+    private void sendError(int msg, int arg1, int arg2) {
+        mHandler.obtainMessage(msg, arg1, arg2);
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
index 34f1655..e5193f5 100644
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -30,18 +30,32 @@
     public void onEnrollResult(int fingerprintId,  int remaining) { }
 
     /**
-     * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+     * Fingerprint touch detected, but not processed yet. Clients will use this message to
+     * determine a good or bad scan before the fingerprint is processed.  This is meant for the
+     * client to provide feedback about the scan or alert the user that recognition is to follow.
      *
-     * @param fingerprintId is the finger the hardware has detected.
-     * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
-     * special meaning - the finger wasn't recognized.
+     * @param acquiredInfo one of:
+     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
+     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
+     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
+     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
+     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
+     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
      */
-    public void onScanned(int fingerprintId, int confidence) { }
+    public void onAcquired(int acquiredInfo) { }
+
+    /**
+     * Fingerprint has been detected and processed.  A non-zero return indicates a valid
+     * fingerprint was detected.
+     *
+     * @param fingerprintId the finger id, or 0 if not recognized.
+     */
+    public void onProcessed(int fingerprintId) { }
 
     /**
      * An error was detected during scan or enrollment.  One of
      * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
-     * {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
+     * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
      * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
      * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
      *
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
deleted file mode 100644
index c7fa7cd..0000000
--- a/core/java/android/service/fingerprint/FingerprintService.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.fingerprint;
-
-import android.app.Service;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Slog;
-
-import java.io.PrintWriter;
-import java.util.HashMap;
-
-/**
- * A service to manage multiple clients that want to access the fingerprint HAL API.
- * The service is responsible for maintaining a list of clients and dispatching all
- * fingerprint -related events.
- *
- * @hide
- */
-public class FingerprintService extends Service {
-    private final String TAG = FingerprintService.class.getSimpleName() +
-            "[" + getClass().getSimpleName() + "]";
-    private static final boolean DEBUG = true;
-    HashMap<IFingerprintServiceReceiver, ClientData> mClients =
-            new HashMap<IFingerprintServiceReceiver, ClientData>();
-
-    private static final int MSG_NOTIFY = 10;
-
-    Handler mHandler = new Handler() {
-        public void handleMessage(android.os.Message msg) {
-            switch (msg.what) {
-                case MSG_NOTIFY:
-                    handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
-                    break;
-
-                default:
-                    Slog.w(TAG, "Unknown message:" + msg.what);
-            }
-        }
-    };
-
-    private static final int STATE_IDLE = 0;
-    private static final int STATE_LISTENING = 1;
-    private static final int STATE_ENROLLING = 2;
-    private static final int STATE_DELETING = 3;
-    private static final long MS_PER_SEC = 1000;
-
-    private static final class ClientData {
-        public IFingerprintServiceReceiver receiver;
-        int state;
-        int userId;
-    }
-
-    @Override
-    public final IBinder onBind(Intent intent) {
-        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
-        return new FingerprintServiceWrapper();
-    }
-
-    // JNI methods to communicate from FingerprintManagerService to HAL
-    native int nativeEnroll(int timeout);
-    native int nativeRemove(int fingerprintId);
-
-    // JNI methods for communicating from HAL to clients
-    void notify(int msg, int arg1, int arg2) {
-        mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
-    }
-
-    void handleNotify(int msg, int arg1, int arg2) {
-        for (int i = 0; i < mClients.size(); i++) {
-            ClientData clientData = mClients.get(i);
-            switch (msg) {
-                case FingerprintManager.FINGERPRINT_ERROR: {
-                    if (clientData.state != STATE_IDLE) {
-                        // FINGERPRINT_ERROR_HW_UNAVAILABLE
-                        // FINGERPRINT_ERROR_BAD_CAPTURE
-                        // FINGERPRINT_ERROR_TIMEOUT
-                        // FINGERPRINT_ERROR_NO_SPACE
-                        final int error = arg1;
-                        clientData.state = STATE_IDLE;
-                        if (clientData.receiver != null) {
-                            try {
-                                clientData.receiver.onError(error);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "can't send message to client. Did it die?", e);
-                            }
-                        }
-                    }
-                }
-                break;
-                case FingerprintManager.FINGERPRINT_SCANNED: {
-                    final int fingerId = arg1;
-                    final int confidence = arg2;
-                    if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
-                        try {
-                            clientData.receiver.onScanned(fingerId, confidence);
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "can't send message to client. Did it die?", e);
-                        }
-                    }
-                    break;
-                }
-                case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
-                    if (clientData.state == STATE_ENROLLING) {
-                        final int fingerId = arg1;
-                        final int remaining = arg2;
-                        if (remaining == 0) {
-                            FingerprintUtils.addFingerprintIdForUser(fingerId,
-                                    getContentResolver(), clientData.userId);
-                            clientData.state = STATE_IDLE; // Nothing left to do
-                        }
-                        if (clientData.receiver != null) {
-                            try {
-                                clientData.receiver.onEnrollResult(fingerId, remaining);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "can't send message to client. Did it die?", e);
-                            }
-                        }
-                    }
-                    break;
-                }
-                case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
-                    int fingerId = arg1;
-                    if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
-                    if (clientData.state == STATE_DELETING) {
-                        FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
-                                clientData.userId);
-                        if (clientData.receiver != null) {
-                            try {
-                                clientData.receiver.onRemoved(fingerId);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "can't send message to client. Did it die?", e);
-                            }
-                        }
-                    }
-                }
-                break;
-            }
-        }
-    }
-
-    int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
-        ClientData clientData = mClients.get(receiver);
-        if (clientData != null) {
-            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
-            clientData.state = STATE_ENROLLING;
-            return nativeEnroll((int) (timeout / MS_PER_SEC));
-        }
-        return -1;
-    }
-
-    int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
-        ClientData clientData = mClients.get(receiver);
-        if (clientData != null) {
-            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
-            clientData.state = STATE_DELETING;
-            // The fingerprint id will be removed when we get confirmation from the HAL
-            return nativeRemove(fingerId);
-        }
-        return -1;
-    }
-
-    void startListening(IFingerprintServiceReceiver receiver, int userId) {
-        ClientData clientData = new ClientData();
-        clientData.state = STATE_LISTENING;
-        clientData.receiver = receiver;
-        clientData.userId = userId;
-        mClients.put(receiver, clientData);
-    }
-
-    void stopListening(IFingerprintServiceReceiver receiver, int userId) {
-        ClientData clientData = mClients.get(receiver);
-        if (clientData != null) {
-            clientData.state = STATE_IDLE;
-            clientData.userId = -1;
-            clientData.receiver = null;
-        }
-        mClients.remove(receiver);
-    }
-
-    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
-        IFingerprintServiceReceiver mReceiver;
-        public int enroll(long timeout, int userId) {
-            return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
-                    : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
-        }
-
-        public int remove(int fingerprintId, int userId) {
-            return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
-        }
-
-        public void startListening(IFingerprintServiceReceiver receiver, int userId) {
-            mReceiver = receiver;
-            FingerprintService.this.startListening(receiver, userId);
-        }
-
-        public void stopListening(int userId) {
-            FingerprintService.this.stopListening(mReceiver, userId);
-        }
-    }
-}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index 81a2aac..f4b5526 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -18,10 +18,12 @@
 
 import android.content.ContentResolver;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.Arrays;
 
+public
 class FingerprintUtils {
     private static final boolean DEBUG = true;
     private static final String TAG = "FingerprintUtils";
@@ -30,13 +32,16 @@
         String fingerIdsRaw = Settings.Secure.getStringForUser(res,
                 Settings.Secure.USER_FINGERPRINT_IDS, userId);
 
-        String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
-        int result[] = new int[fingerStringIds.length];
-        for (int i = 0; i < result.length; i++) {
-            try {
-                result[i] = Integer.decode(fingerStringIds[i]);
-            } catch (NumberFormatException e) {
-                if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+        int result[] = {};
+        if (!TextUtils.isEmpty(fingerIdsRaw)) {
+            String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+            result = new int[fingerStringIds.length];
+            for (int i = 0; i < result.length; i++) {
+                try {
+                    result[i] = Integer.decode(fingerStringIds[i]);
+                } catch (NumberFormatException e) {
+                    if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+                }
             }
         }
         return result;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index e92c20c..43d5e9a 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -22,17 +22,20 @@
  * Communication channel from client to the fingerprint service.
  * @hide
  */
-interface IFingerprintService {
-    // Returns 0 if successfully started, -1 otherwise
-    int enroll(long timeout, int userId);
+oneway interface IFingerprintService {
+    // Any errors resulting from this call will be returned to the listener
+    void enroll(IBinder token, long timeout, int userId);
+    
+    // Any errors resulting from this call will be returned to the listener
+    void enrollCancel(IBinder token, int userId);
 
-    // Returns 0 if fingerprintId's template can be removed, -1 otherwise
-    int remove(int fingerprintId, int userId);
+    // Any errors resulting from this call will be returned to the listener
+    void remove(IBinder token, int fingerprintId, int userId);
 
     // Start listening for fingerprint events.  This has the side effect of starting
     // the hardware if not already started.
-    oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+    void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
 
     // Stops listening for fingerprints
-    oneway void stopListening(int userId);
+    void stopListening(IBinder token, int userId);
 }
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index 4826b59..af4128f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -24,7 +24,8 @@
  */
 oneway interface IFingerprintServiceReceiver {
     void onEnrollResult(int fingerprintId,  int remaining);
-    void onScanned(int fingerprintId, int confidence);
+    void onAcquired(int acquiredInfo);
+    void onProcessed(int fingerprintId);
     void onError(int error);
     void onRemoved(int fingerprintId);
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index fd475cd..8bd0f4d 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -29,6 +29,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import java.util.List;
@@ -54,7 +55,7 @@
             + "[" + getClass().getSimpleName() + "]";
 
     private INotificationListenerWrapper mWrapper = null;
-    private Ranking mRanking;
+    private RankingMap mRankingMap;
 
     private INotificationManager mNoMan;
 
@@ -75,7 +76,22 @@
      *            object as well as its identifying information (tag and id) and source
      *            (package name).
      */
-    public abstract void onNotificationPosted(StatusBarNotification sbn);
+    public void onNotificationPosted(StatusBarNotification sbn) {
+        // optional
+    }
+
+    /**
+     * Implement this method to learn about new notifications as they are posted by apps.
+     *
+     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
+     *            object as well as its identifying information (tag and id) and source
+     *            (package name).
+     * @param rankingMap The current ranking map that can be used to retrieve ranking information
+     *                   for active notifications, including the newly posted one.
+     */
+    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+        onNotificationPosted(sbn);
+    }
 
     /**
      * Implement this method to learn when notifications are removed.
@@ -94,7 +110,33 @@
      *            and source (package name) used to post the {@link android.app.Notification} that
      *            was just removed.
      */
-    public abstract void onNotificationRemoved(StatusBarNotification sbn);
+    public void onNotificationRemoved(StatusBarNotification sbn) {
+        // optional
+    }
+
+    /**
+     * Implement this method to learn when notifications are removed.
+     * <P>
+     * This might occur because the user has dismissed the notification using system UI (or another
+     * notification listener) or because the app has withdrawn the notification.
+     * <P>
+     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
+     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
+     * fields such as {@link android.app.Notification#contentView} and
+     * {@link android.app.Notification#largeIcon}. However, all other fields on
+     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
+     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
+     *
+     * @param sbn A data structure encapsulating at least the original information (tag and id)
+     *            and source (package name) used to post the {@link android.app.Notification} that
+     *            was just removed.
+     * @param rankingMap The current ranking map that can be used to retrieve ranking information
+     *                   for active notifications.
+     *
+     */
+    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+        onNotificationRemoved(sbn);
+    }
 
     /**
      * Implement this method to learn about when the listener is enabled and connected to
@@ -107,10 +149,11 @@
 
     /**
      * Implement this method to be notified when the notification ranking changes.
-     * <P>
-     * Call {@link #getCurrentRanking()} to retrieve the new ranking.
+     *
+     * @param rankingMap The current ranking map that can be used to retrieve ranking information
+     *                   for active notifications.
      */
-    public void onNotificationRankingUpdate() {
+    public void onNotificationRankingUpdate(RankingMap rankingMap) {
         // optional
     }
 
@@ -241,16 +284,19 @@
      *
      * <p>
      * The returned object represents the current ranking snapshot and only
-     * applies for currently active notifications. Hence you must retrieve a
-     * new Ranking after each notification event such as
-     * {@link #onNotificationPosted(StatusBarNotification)},
-     * {@link #onNotificationRemoved(StatusBarNotification)}, etc.
+     * applies for currently active notifications.
+     * <p>
+     * Generally you should use the RankingMap that is passed with events such
+     * as {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
+     * {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and
+     * so on. This method should only be used when needing access outside of
+     * such events, for example to retrieve the RankingMap right after
+     * initialization.
      *
-     * @return A {@link NotificationListenerService.Ranking} object providing
-     *     access to ranking information
+     * @return A {@link RankingMap} object providing access to ranking information
      */
-    public Ranking getCurrentRanking() {
-        return mRanking;
+    public RankingMap getCurrentRanking() {
+        return mRankingMap;
     }
 
     @Override
@@ -313,7 +359,7 @@
             synchronized (mWrapper) {
                 applyUpdate(update);
                 try {
-                    NotificationListenerService.this.onNotificationPosted(sbn);
+                    NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
                 } catch (Throwable t) {
                     Log.w(TAG, "Error running onNotificationPosted", t);
                 }
@@ -326,7 +372,7 @@
             synchronized (mWrapper) {
                 applyUpdate(update);
                 try {
-                    NotificationListenerService.this.onNotificationRemoved(sbn);
+                    NotificationListenerService.this.onNotificationRemoved(sbn, mRankingMap);
                 } catch (Throwable t) {
                     Log.w(TAG, "Error running onNotificationRemoved", t);
                 }
@@ -351,7 +397,7 @@
             synchronized (mWrapper) {
                 applyUpdate(update);
                 try {
-                    NotificationListenerService.this.onNotificationRankingUpdate();
+                    NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
                 } catch (Throwable t) {
                     Log.w(TAG, "Error running onNotificationRankingUpdate", t);
                 }
@@ -360,7 +406,65 @@
     }
 
     private void applyUpdate(NotificationRankingUpdate update) {
-        mRanking = new Ranking(update);
+        mRankingMap = new RankingMap(update);
+    }
+
+    /**
+     * Provides access to ranking information on a currently active
+     * notification.
+     *
+     * <p>
+     * Note that this object is not updated on notification events (such as
+     * {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
+     * {@link #onNotificationRemoved(StatusBarNotification)}, etc.). Make sure
+     * to retrieve a new Ranking from the current {@link RankingMap} whenever
+     * a notification event occurs.
+     */
+    public static class Ranking {
+        private final String mKey;
+        private final int mRank;
+        private final boolean mIsAmbient;
+        private final boolean mIsInterceptedByDnd;
+
+        private Ranking(String key, int rank, boolean isAmbient, boolean isInterceptedByDnd) {
+            mKey = key;
+            mRank = rank;
+            mIsAmbient = isAmbient;
+            mIsInterceptedByDnd = isInterceptedByDnd;
+        }
+
+        /**
+         * Returns the key of the notification this Ranking applies to.
+         */
+        public String getKey() {
+            return mKey;
+        }
+
+        /**
+         * Returns the rank of the notification.
+         *
+         * @return the rank of the notification, that is the 0-based index in
+         *     the list of active notifications.
+         */
+        public int getRank() {
+            return mRank;
+        }
+
+        /**
+         * Returns whether the notification is an ambient notification, that is
+         * a notification that doesn't require the user's immediate attention.
+         */
+        public boolean isAmbient() {
+            return mIsAmbient;
+        }
+
+        /**
+         * Returns whether the notification was intercepted by
+         * &quot;Do not disturb&quot;.
+         */
+        public boolean isInterceptedByDoNotDisturb() {
+            return mIsInterceptedByDnd;
+        }
     }
 
     /**
@@ -371,11 +475,14 @@
      * Note that this object represents a ranking snapshot that only applies to
      * notifications active at the time of retrieval.
      */
-    public static class Ranking implements Parcelable {
+    public static class RankingMap implements Parcelable {
         private final NotificationRankingUpdate mRankingUpdate;
+        private final ArrayMap<String, Ranking> mRankingCache;
+        private boolean mRankingCacheInitialized;
 
-        private Ranking(NotificationRankingUpdate rankingUpdate) {
+        private RankingMap(NotificationRankingUpdate rankingUpdate) {
             mRankingUpdate = rankingUpdate;
+            mRankingCache = new ArrayMap<>(rankingUpdate.getOrderedKeys().length);
         }
 
         /**
@@ -389,56 +496,37 @@
         }
 
         /**
-         * Returns the rank of the notification with the given key, that is the
-         * index of <code>key</code> in the array of keys returned by
-         * {@link #getOrderedKeys()}.
+         * Returns the Ranking for the notification with the given key.
          *
-         * @return The rank of the notification with the given key; -1 when the
-         *      given key is unknown.
+         * @return the Ranking of the notification with the given key;
+         *     <code>null</code> when the key is unknown.
          */
-        public int getRank(String key) {
-            // TODO: Optimize.
+        public Ranking getRanking(String key) {
+            synchronized (mRankingCache) {
+                if (!mRankingCacheInitialized) {
+                    initializeRankingCache();
+                    mRankingCacheInitialized = true;
+                }
+            }
+            return mRankingCache.get(key);
+        }
+
+        private void initializeRankingCache() {
             String[] orderedKeys = mRankingUpdate.getOrderedKeys();
-            for (int i = 0; i < orderedKeys.length; i++) {
-                if (orderedKeys[i].equals(key)) {
-                    return i;
-                }
-            }
-            return -1;
-        }
-
-        /**
-         * Returns whether the notification with the given key was intercepted
-         * by &quot;Do not disturb&quot;.
-         */
-        public boolean isInterceptedByDoNotDisturb(String key) {
-            // TODO: Optimize.
-            for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) {
-                if (interceptedKey.equals(key)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Returns whether the notification with the given key is an ambient
-         * notification, that is a notification that doesn't require the user's
-         * immediate attention.
-         */
-        public boolean isAmbient(String key) {
-            // TODO: Optimize.
             int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
-            if (firstAmbientIndex < 0) {
-                return false;
-            }
-            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
-            for (int i = firstAmbientIndex; i < orderedKeys.length; i++) {
-                if (orderedKeys[i].equals(key)) {
-                    return true;
+            for (int i = 0; i < orderedKeys.length; i++) {
+                String key = orderedKeys[i];
+                boolean isAmbient = firstAmbientIndex > -1 && firstAmbientIndex <= i;
+                boolean isInterceptedByDnd = false;
+                // TODO: Optimize.
+                for (String s : mRankingUpdate.getDndInterceptedKeys()) {
+                    if (s.equals(key)) {
+                        isInterceptedByDnd = true;
+                        break;
+                    }
                 }
+                mRankingCache.put(key, new Ranking(key, i, isAmbient, isInterceptedByDnd));
             }
-            return false;
         }
 
         // ----------- Parcelable
@@ -453,16 +541,16 @@
             dest.writeParcelable(mRankingUpdate, flags);
         }
 
-        public static final Creator<Ranking> CREATOR = new Creator<Ranking>() {
+        public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() {
             @Override
-            public Ranking createFromParcel(Parcel source) {
+            public RankingMap createFromParcel(Parcel source) {
                 NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
-                return new Ranking(rankingUpdate);
+                return new RankingMap(rankingUpdate);
             }
 
             @Override
-            public Ranking[] newArray(int size) {
-                return new Ranking[size];
+            public RankingMap[] newArray(int size) {
+                return new RankingMap[size];
             }
         };
     }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index a6cddae..8fa45e6 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -80,6 +80,11 @@
 
     private ITrustAgentServiceCallback mCallback;
 
+    private Runnable mPendingGrantTrustTask;
+
+    // Lock used to access mPendingGrantTrustTask and mCallback.
+    private final Object mLock = new Object();
+
     private Handler mHandler = new Handler() {
         public void handleMessage(android.os.Message msg) {
             switch (msg.what) {
@@ -127,12 +132,24 @@
      * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
      *                        the user is about to use the device.
      */
-    public final void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser) {
-        if (mCallback != null) {
-            try {
-                mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
-            } catch (RemoteException e) {
-                onError("calling enableTrust()");
+    public final void grantTrust(
+            final CharSequence message, final long durationMs, final boolean initiatedByUser) {
+        synchronized (mLock) {
+            if (mCallback != null) {
+                try {
+                    mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
+                } catch (RemoteException e) {
+                    onError("calling enableTrust()");
+                }
+            } else {
+                // Remember trust has been granted so we can effectively grant it once the service
+                // is bound.
+                mPendingGrantTrustTask = new Runnable() {
+                    @Override
+                    public void run() {
+                        grantTrust(message, durationMs, initiatedByUser);
+                    }
+                };
             }
         }
     }
@@ -141,11 +158,16 @@
      * Call to revoke trust on the device.
      */
     public final void revokeTrust() {
-        if (mCallback != null) {
-            try {
-                mCallback.revokeTrust();
-            } catch (RemoteException e) {
-                onError("calling revokeTrust()");
+        synchronized (mLock) {
+            if (mPendingGrantTrustTask != null) {
+                mPendingGrantTrustTask = null;
+            }
+            if (mCallback != null) {
+                try {
+                    mCallback.revokeTrust();
+                } catch (RemoteException e) {
+                    onError("calling revokeTrust()");
+                }
             }
         }
     }
@@ -164,7 +186,13 @@
         }
 
         public void setCallback(ITrustAgentServiceCallback callback) {
-            mCallback = callback;
+            synchronized (mLock) {
+                mCallback = callback;
+                if (mPendingGrantTrustTask != null) {
+                    mPendingGrantTrustTask.run();
+                    mPendingGrantTrustTask = null;
+                }
+            }
         }
     }
 
diff --git a/core/java/android/service/voice/DspInfo.java b/core/java/android/service/voice/DspInfo.java
new file mode 100644
index 0000000..0862309
--- /dev/null
+++ b/core/java/android/service/voice/DspInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.voice;
+
+import java.util.UUID;
+
+/**
+ * Properties of the DSP hardware on the device.
+ * @hide
+ */
+public class DspInfo {
+    /**
+     * Unique voice engine Id (changes with each version).
+     */
+    public final UUID voiceEngineId;
+
+    /**
+     * Human readable voice detection engine implementor.
+     */
+    public final String voiceEngineImplementor;
+    /**
+     * Human readable voice detection engine description.
+     */
+    public final String voiceEngineDescription;
+    /**
+     * Human readable voice detection engine version
+     */
+    public final int voiceEngineVersion;
+    /**
+     * Rated power consumption when detection is active.
+     */
+    public final int powerConsumptionMw;
+
+    public DspInfo(UUID voiceEngineId, String voiceEngineImplementor,
+            String voiceEngineDescription, int version, int powerConsumptionMw) {
+        this.voiceEngineId = voiceEngineId;
+        this.voiceEngineImplementor = voiceEngineImplementor;
+        this.voiceEngineDescription = voiceEngineDescription;
+        this.voiceEngineVersion = version;
+        this.powerConsumptionMw = powerConsumptionMw;
+    }
+}
diff --git a/core/java/android/service/voice/KeyphraseEnrollmentInfo.java b/core/java/android/service/voice/KeyphraseEnrollmentInfo.java
new file mode 100644
index 0000000..ebe41ce
--- /dev/null
+++ b/core/java/android/service/voice/KeyphraseEnrollmentInfo.java
@@ -0,0 +1,246 @@
+/*
+ * 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.service.voice;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+/** @hide */
+public class KeyphraseEnrollmentInfo {
+    private static final String TAG = "KeyphraseEnrollmentInfo";
+    /**
+     * Name under which a Hotword enrollment component publishes information about itself.
+     * This meta-data should reference an XML resource containing a
+     * <code>&lt;{@link
+     * android.R.styleable#VoiceEnrollmentApplication
+     * voice-enrollment-application}&gt;</code> tag.
+     */
+    private static final String VOICE_KEYPHRASE_META_DATA = "android.voice_enrollment";
+    /**
+     * Activity Action: Show activity for managing the keyphrases for hotword detection.
+     * This needs to be defined by an activity that supports enrolling users for hotword/keyphrase
+     * detection.
+     */
+    public static final String ACTION_MANAGE_VOICE_KEYPHRASES =
+            "com.android.intent.action.MANAGE_VOICE_KEYPHRASES";
+    /**
+     * Intent extra: The intent extra for un-enrolling a user for a particular keyphrase.
+     */
+    public static final String EXTRA_VOICE_KEYPHRASE_UNENROLL =
+            "com.android.intent.extra.VOICE_KEYPHRASE_UNENROLL";
+    /**
+     * Intent extra: The hint text to be shown on the voice keyphrase management UI.
+     */
+    public static final String EXTRA_VOICE_KEYPHRASE_HINT_TEXT =
+            "com.android.intent.extra.VOICE_KEYPHRASE_HINT_TEXT";
+    /**
+     * Intent extra: The voice locale to use while managing the keyphrase.
+     */
+    public static final String EXTRA_VOICE_KEYPHRASE_LOCALE =
+            "com.android.intent.extra.VOICE_KEYPHRASE_LOCALE";
+
+    private KeyphraseInfo[] mKeyphrases;
+    private String mEnrollmentPackage;
+    private String mParseError;
+
+    public KeyphraseEnrollmentInfo(PackageManager pm) {
+        // Find the apps that supports enrollment for hotword keyhphrases,
+        // Pick a privileged app and obtain the information about the supported keyphrases
+        // from its metadata.
+        List<ResolveInfo> ris = pm.queryIntentActivities(
+                new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY);
+        if (ris == null || ris.isEmpty()) {
+            // No application capable of enrolling for voice keyphrases is present.
+            mParseError = "No enrollment application found";
+            return;
+        }
+
+        boolean found = false;
+        ApplicationInfo ai = null;
+        for (ResolveInfo ri : ris) {
+            try {
+                ai = pm.getApplicationInfo(
+                        ri.activityInfo.packageName, PackageManager.GET_META_DATA);
+                if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+                    // The application isn't privileged (/system/priv-app).
+                    // The enrollment application needs to be a privileged system app.
+                    Slog.w(TAG, ai.packageName + "is not a privileged system app");
+                    continue;
+                }
+                if (!Manifest.permission.MANAGE_VOICE_KEYPHRASES.equals(ai.permission)) {
+                    // The application trying to manage keyphrases doesn't
+                    // require the MANAGE_VOICE_KEYPHRASES permission.
+                    Slog.w(TAG, ai.packageName + " does not require MANAGE_VOICE_KEYPHRASES");
+                    continue;
+                }
+                mEnrollmentPackage = ai.packageName;
+                found = true;
+                break;
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.w(TAG, "error parsing voice enrollment meta-data", e);
+            }
+        }
+
+        if (!found) {
+            mKeyphrases = null;
+            mParseError = "No suitable enrollment application found";
+            return;
+        }
+
+        XmlResourceParser parser = null;
+        try {
+            parser = ai.loadXmlMetaData(pm, VOICE_KEYPHRASE_META_DATA);
+            if (parser == null) {
+                mParseError = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for "
+                        + ai.packageName;
+                return;
+            }
+
+            Resources res = pm.getResourcesForApplication(ai);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+
+            String nodeName = parser.getName();
+            if (!"voice-enrollment-application".equals(nodeName)) {
+                mParseError = "Meta-data does not start with voice-enrollment-application tag";
+                return;
+            }
+
+            TypedArray array = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.VoiceEnrollmentApplication);
+            int searchKeyphraseId = array.getInt(
+                    com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId,
+                    -1);
+            if (searchKeyphraseId != -1) {
+                String searchKeyphrase = array.getString(com.android.internal.R.styleable
+                        .VoiceEnrollmentApplication_searchKeyphrase);
+                String searchKeyphraseSupportedLocales =
+                        array.getString(com.android.internal.R.styleable
+                                .VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
+                String[] supportedLocales = new String[0];
+                // Get all the supported locales from the comma-delimted string.
+                if (searchKeyphraseSupportedLocales != null
+                        && !searchKeyphraseSupportedLocales.isEmpty()) {
+                    supportedLocales = searchKeyphraseSupportedLocales.split(",");
+                }
+                mKeyphrases = new KeyphraseInfo[1];
+                mKeyphrases[0] = new KeyphraseInfo(
+                        searchKeyphraseId, searchKeyphrase, supportedLocales);
+            } else {
+                mParseError = "searchKeyphraseId not specified in meta-data";
+                return;
+            }
+        } catch (XmlPullParserException e) {
+            mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+            Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+            return;
+        } catch (IOException e) {
+            mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+            Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+            return;
+        } catch (PackageManager.NameNotFoundException e) {
+            mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+            Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+            return;
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    public String getParseError() {
+        return mParseError;
+    }
+
+    /**
+     * @return An array of available keyphrases that can be enrolled on the system.
+     *         It may be null if no keyphrases can be enrolled.
+     */
+    public KeyphraseInfo[] getKeyphrases() {
+        return mKeyphrases;
+    }
+
+    /**
+     * Returns an intent to launch an activity that manages the given keyphrase
+     * for the locale.
+     *
+     * @param enroll Indicates if the intent should enroll the user or un-enroll them.
+     * @param keyphrase The keyphrase that the user needs to be enrolled to.
+     * @param locale The locale for which the enrollment needs to be performed.
+     * @return An {@link Intent} to manage the keyphrase. This can be null if managing the
+     *         given keyphrase/locale combination isn't possible.
+     */
+    public Intent getManageKeyphraseIntent(boolean enroll, String keyphrase, String locale) {
+        if (mEnrollmentPackage == null || mEnrollmentPackage.isEmpty()) {
+            Slog.w(TAG, "No enrollment application exists");
+            return null;
+        }
+
+        if (isKeyphraseEnrollmentSupported(keyphrase, locale)) {
+            Intent intent = new Intent(ACTION_MANAGE_VOICE_KEYPHRASES)
+                    .setPackage(mEnrollmentPackage)
+                    .putExtra(EXTRA_VOICE_KEYPHRASE_HINT_TEXT, keyphrase)
+                    .putExtra(EXTRA_VOICE_KEYPHRASE_LOCALE, locale);
+            if (!enroll) intent.putExtra(EXTRA_VOICE_KEYPHRASE_UNENROLL, true);
+            return intent;
+        }
+        return null;
+    }
+
+    /**
+     * Indicates if enrollment is supported for the given keyphrase & locale.
+     *
+     * @param keyphrase The keyphrase that the user needs to be enrolled to.
+     * @param locale The locale for which the enrollment needs to be performed.
+     * @return true, if an enrollment client supports the given keyphrase and the given locale.
+     */
+    public boolean isKeyphraseEnrollmentSupported(String keyphrase, String locale) {
+        if (mKeyphrases == null || mKeyphrases.length == 0) {
+            Slog.w(TAG, "Enrollment application doesn't support keyphrases");
+            return false;
+        }
+        for (KeyphraseInfo keyphraseInfo : mKeyphrases) {
+            // Check if the given keyphrase is supported in the locale provided by
+            // the enrollment application.
+            String supportedKeyphrase = keyphraseInfo.keyphrase;
+            if (supportedKeyphrase.equalsIgnoreCase(keyphrase)
+                    && keyphraseInfo.supportedLocales.contains(locale)) {
+                return true;
+            }
+        }
+        Slog.w(TAG, "Enrollment application doesn't support the given keyphrase");
+        return false;
+    }
+}
diff --git a/core/java/android/service/voice/KeyphraseInfo.java b/core/java/android/service/voice/KeyphraseInfo.java
new file mode 100644
index 0000000..d266e1a
--- /dev/null
+++ b/core/java/android/service/voice/KeyphraseInfo.java
@@ -0,0 +1,27 @@
+package android.service.voice;
+
+import android.util.ArraySet;
+
+/**
+ * A Voice Keyphrase.
+ * @hide
+ */
+public class KeyphraseInfo {
+    public final int id;
+    public final String keyphrase;
+    public final ArraySet<String> supportedLocales;
+
+    public KeyphraseInfo(int id, String keyphrase, String[] supportedLocales) {
+        this.id = id;
+        this.keyphrase = keyphrase;
+        this.supportedLocales = new ArraySet<String>(supportedLocales.length);
+        for (String locale : supportedLocales) {
+            this.supportedLocales.add(locale);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "id=" + id + ", keyphrase=" + keyphrase + ", supported-locales=" + supportedLocales;
+    }
+}
diff --git a/core/java/android/service/voice/SoundTriggerManager.java b/core/java/android/service/voice/SoundTriggerManager.java
new file mode 100644
index 0000000..2d049b9
--- /dev/null
+++ b/core/java/android/service/voice/SoundTriggerManager.java
@@ -0,0 +1,73 @@
+/*
+ * 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.service.voice;
+
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
+
+import java.util.ArrayList;
+
+/**
+ * Manager for {@link SoundTrigger} APIs.
+ * Currently this just acts as an abstraction over all SoundTrigger API calls.
+ * @hide
+ */
+public class SoundTriggerManager {
+    /** The {@link DspInfo} for the system, or null if none exists. */
+    public DspInfo dspInfo;
+
+    public SoundTriggerManager() {
+        ArrayList <ModuleProperties> modules = new ArrayList<>();
+        int status = SoundTrigger.listModules(modules);
+        if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
+            // TODO(sansid, elaurent): Figure out how to handle errors in listing the modules here.
+            dspInfo = null;
+        } else {
+            // TODO(sansid, elaurent): Figure out how to determine which module corresponds to the
+            // DSP hardware.
+            ModuleProperties properties = modules.get(0);
+            dspInfo = new DspInfo(properties.uuid, properties.implementor, properties.description,
+                    properties.version, properties.powerConsumptionMw);
+        }
+    }
+
+    /**
+     * @return True, if the keyphrase is supported on DSP for the given locale.
+     */
+    public boolean isKeyphraseSupported(String keyphrase, String locale) {
+        // TODO(sansid): We also need to look into a SoundTrigger API that let's us
+        // query this. For now just return supported if there's a DSP available.
+        return dspInfo != null;
+    }
+
+    /**
+     * @return True, if the keyphrase is has been enrolled for the given locale.
+     */
+    public boolean isKeyphraseEnrolled(String keyphrase, String locale) {
+        // TODO(sansid, elaurent): Query SoundTrigger to list currently loaded sound models.
+        // They have been enrolled.
+        return false;
+    }
+
+    /**
+     * @return True, if a recognition for the keyphrase is active for the given locale.
+     */
+    public boolean isKeyphraseActive(String keyphrase, String locale) {
+        // TODO(sansid, elaurent): Check if the recognition for the keyphrase is currently active.
+        return false;
+    }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index e15489b..e0329f8 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -17,7 +17,6 @@
 package android.service.voice;
 
 import android.annotation.SdkConstant;
-import android.app.Instrumentation;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -25,8 +24,11 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractionManagerService;
 
+
 /**
  * Top-level service of the current global voice interactor, which is providing
  * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
@@ -51,6 +53,16 @@
     public static final String SERVICE_INTERFACE =
             "android.service.voice.VoiceInteractionService";
 
+    // TODO(sansid): Unhide these.
+    /** @hide */
+    public static final int KEYPHRASE_UNAVAILABLE = 0;
+    /** @hide */
+    public static final int KEYPHRASE_UNENROLLED = 1;
+    /** @hide */
+    public static final int KEYPHRASE_ENROLLED = 2;
+    /** @hide */
+    public static final int KEYPHRASE_ACTIVE = 3;
+
     /**
      * Name under which a VoiceInteractionService component publishes information about itself.
      * This meta-data should reference an XML resource containing a
@@ -64,6 +76,9 @@
 
     IVoiceInteractionManagerService mSystemService;
 
+    private SoundTriggerManager mSoundTriggerManager;
+    private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
+
     public void startSession(Bundle args) {
         try {
             mSystemService.startSession(mInterface, args);
@@ -76,6 +91,8 @@
         super.onCreate();
         mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+        mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager());
+        mSoundTriggerManager = new SoundTriggerManager();
     }
 
     @Override
@@ -85,4 +102,44 @@
         }
         return null;
     }
+
+    /**
+     * Gets the state of always-on hotword detection for the given keyphrase and locale
+     * on this system.
+     * Availability implies that the hardware on this system is capable of listening for
+     * the given keyphrase or not.
+     * The return code is one of {@link #KEYPHRASE_UNAVAILABLE}, {@link #KEYPHRASE_UNENROLLED}
+     * {@link #KEYPHRASE_ENROLLED} or {@link #KEYPHRASE_ACTIVE}.
+     *
+     * @param keyphrase The keyphrase whose availability is being checked.
+     * @param locale The locale for which the availability is being checked.
+     * @return Indicates if always-on hotword detection is available for the given keyphrase.
+     * TODO(sansid): Unhide this.
+     * @hide
+     */
+    public final int getAlwaysOnKeyphraseAvailability(String keyphrase, String locale) {
+        // The available keyphrases is a combination of DSP availability and
+        // the keyphrases that have an enrollment application for them.
+        if (!mSoundTriggerManager.isKeyphraseSupported(keyphrase, locale)
+                || !mKeyphraseEnrollmentInfo.isKeyphraseEnrollmentSupported(keyphrase, locale)) {
+            return KEYPHRASE_UNAVAILABLE;
+        }
+        if (!mSoundTriggerManager.isKeyphraseEnrolled(keyphrase, locale)) {
+            return KEYPHRASE_UNENROLLED;
+        }
+        if (!mSoundTriggerManager.isKeyphraseActive(keyphrase, locale)) {
+            return KEYPHRASE_ENROLLED;
+        } else {
+            return KEYPHRASE_ACTIVE;
+        }
+    }
+
+    /**
+     * @return Details of keyphrases available for enrollment.
+     * @hide
+     */
+    @VisibleForTesting
+    protected final KeyphraseEnrollmentInfo getKeyphraseEnrollmentInfo() {
+        return mKeyphraseEnrollmentInfo;
+    }
 }
diff --git a/core/java/android/speech/tts/RequestConfig.java b/core/java/android/speech/tts/RequestConfig.java
index 4b5385f..84880c0 100644
--- a/core/java/android/speech/tts/RequestConfig.java
+++ b/core/java/android/speech/tts/RequestConfig.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
 
 import android.media.AudioManager;
diff --git a/core/java/android/speech/tts/RequestConfigHelper.java b/core/java/android/speech/tts/RequestConfigHelper.java
index b25c985..bc65280 100644
--- a/core/java/android/speech/tts/RequestConfigHelper.java
+++ b/core/java/android/speech/tts/RequestConfigHelper.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
 
 import android.speech.tts.TextToSpeechClient.EngineStatus;
@@ -31,7 +46,8 @@
 
         /**
          * Score positively voices that exactly match the given locale
-         * @param locale Reference locale. If null, the default locale will be used.
+         * @param locale Reference locale. If null, the system default locale for the
+         * current user will be used ({@link Locale#getDefault()}).
          */
         public ExactLocaleMatcher(Locale locale) {
             if (locale == null) {
@@ -55,7 +71,8 @@
 
         /**
          * Score positively voices with similar locale.
-         * @param locale Reference locale. If null, default will be used.
+         * @param locale Reference locale.  If null, the system default locale for the
+         * current user will be used ({@link Locale#getDefault()}).
          */
         public LanguageMatcher(Locale locale) {
             if (locale == null) {
@@ -149,10 +166,10 @@
     }
 
     /**
-     * Get highest quality voice for the default locale.
+     * Get highest quality voice for the TTS default locale.
      *
      * Call {@link #highestQuality(EngineStatus, boolean, VoiceScorer)} with
-     * {@link LanguageMatcher} set to device default locale.
+     * {@link LanguageMatcher} set to the {@link EngineStatus#getDefaultLocale()}.
      *
      * @param engineStatus
      *            Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call.
@@ -164,7 +181,7 @@
     public static RequestConfig highestQuality(EngineStatus engineStatus,
             boolean hasToBeEmbedded) {
         return highestQuality(engineStatus, hasToBeEmbedded,
-                new LanguageMatcher(Locale.getDefault()));
+                new LanguageMatcher(engineStatus.getDefaultLocale()));
     }
 
 }
diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java
index 130e3f9..938458c9 100644
--- a/core/java/android/speech/tts/SynthesisRequestV2.java
+++ b/core/java/android/speech/tts/SynthesisRequestV2.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
 
 import android.os.Bundle;
@@ -152,9 +167,7 @@
         }
     };
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 0c0be83..f726743 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -42,6 +42,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -357,9 +358,13 @@
         /** Name of the TTS engine package */
         private final String mPackageName;
 
-        private EngineStatus(String packageName, List<VoiceInfo> voices) {
+        /** Engine default locale */
+        private final Locale mDefaultLocale;
+
+        private EngineStatus(String packageName, List<VoiceInfo> voices, Locale defaultLocale) {
             this.mVoices =  Collections.unmodifiableList(voices);
             this.mPackageName = packageName;
+            this.mDefaultLocale = defaultLocale;
         }
 
         /**
@@ -375,6 +380,16 @@
         public String getEnginePackage() {
             return mPackageName;
         }
+
+        /**
+         * Get the default locale to use for TTS with this TTS engine.
+         * Unless the user changed the TTS settings for this engine, the value returned should be
+         * the same as the system default locale for the current user
+         * ({@link Locale#getDefault()}).
+         */
+        public Locale getDefaultLocale() {
+            return mDefaultLocale;
+        }
     }
 
     /** Unique synthesis request identifier. */
@@ -638,7 +653,9 @@
             return null;
         }
 
-        return new EngineStatus(mServiceConnection.getEngineName(), voices);
+        return new EngineStatus(mServiceConnection.getEngineName(), voices,
+                mEnginesHelper.getLocalePrefForEngine(
+                        mServiceConnection.getEngineName()));
     }
 
     private class Connection implements ServiceConnection {
@@ -696,7 +713,9 @@
             public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) {
                 synchronized (mLock) {
                     mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
-                            voicesInfo);
+                            voicesInfo,
+                            mEnginesHelper.getLocalePrefForEngine(
+                                    mServiceConnection.getEngineName()));
                     mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
                             mEngineStatus).sendToTarget();
                 }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 14a4024..20f3ad7 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -460,8 +460,8 @@
     }
 
     private String[] getSettingsLocale() {
-        final String locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
-        return TtsEngines.parseLocalePref(locale);
+        final Locale locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
+        return TtsEngines.toOldLocaleStringFormat(locale);
     }
 
     private int getSecureSettingInt(String name, int defaultValue) {
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 9b929a3..7474efe 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -28,6 +28,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+
 import static android.provider.Settings.Secure.getString;
 
 import android.provider.Settings;
@@ -42,8 +43,10 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.MissingResourceException;
 
 /**
@@ -53,16 +56,52 @@
  * Comments in this class the use the shorthand "system engines" for engines that
  * are a part of the system image.
  *
+ * This class is thread-safe/
+ *
  * @hide
  */
 public class TtsEngines {
     private static final String TAG = "TtsEngines";
     private static final boolean DBG = false;
 
-    private static final String LOCALE_DELIMITER = "-";
+    /** Locale delimiter used by the old-style 3 char locale string format (like "eng-usa") */
+    private static final String LOCALE_DELIMITER_OLD = "-";
+
+    /** Locale delimiter used by the new-style locale string format (Locale.toString() results,
+     * like "en_US") */
+    private static final String LOCALE_DELIMITER_NEW = "_";
 
     private final Context mContext;
 
+    /** Mapping of various language strings to the normalized Locale form */
+    private static final Map<String, String> sNormalizeLanguage;
+
+    /** Mapping of various country strings to the normalized Locale form */
+    private static final Map<String, String> sNormalizeCountry;
+
+    // Populate the sNormalize* maps
+    static {
+        HashMap<String, String> normalizeLanguage = new HashMap<String, String>();
+        for (String language : Locale.getISOLanguages()) {
+            try {
+                normalizeLanguage.put(new Locale(language).getISO3Language(), language);
+            } catch (MissingResourceException e) {
+                continue;
+            }
+        }
+        sNormalizeLanguage = Collections.unmodifiableMap(normalizeLanguage);
+
+        HashMap<String, String> normalizeCountry = new HashMap<String, String>();
+        for (String country : Locale.getISOCountries()) {
+            try {
+                normalizeCountry.put(new Locale("", country).getISO3Country(), country);
+            } catch (MissingResourceException e) {
+                continue;
+            }
+        }
+        sNormalizeCountry = Collections.unmodifiableMap(normalizeCountry);
+    }
+
     public TtsEngines(Context ctx) {
         mContext = ctx;
     }
@@ -282,139 +321,139 @@
     }
 
     /**
-     * Returns the locale string for a given TTS engine. Attempts to read the
+     * Returns the default locale for a given TTS engine. Attempts to read the
      * value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
-     * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
-     * both these values are empty, the default phone locale is returned.
+     * default phone locale is returned.
      *
      * @param engineName the engine to return the locale for.
-     * @return the locale string preference for this engine. Will be non null
-     *         and non empty.
+     * @return the locale preference for this engine. Will be non null.
      */
-    public String getLocalePrefForEngine(String engineName) {
-        String locale = parseEnginePrefFromList(
-                getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
-                engineName);
-
-        if (TextUtils.isEmpty(locale)) {
-            // The new style setting is unset, attempt to return the old style setting.
-            locale = getV1Locale();
-        }
-
-        if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + locale);
-
-        return locale;
+    public Locale getLocalePrefForEngine(String engineName) {
+        return getLocalePrefForEngine(engineName,
+                getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE));
     }
 
     /**
+     * Returns the default locale for a given TTS engine from given settings string. */
+    public Locale getLocalePrefForEngine(String engineName, String prefValue) {
+        String localeString = parseEnginePrefFromList(
+                prefValue,
+                engineName);
+
+        if (TextUtils.isEmpty(localeString)) {
+            // The new style setting is unset, attempt to return the old style setting.
+            return Locale.getDefault();
+        }
+
+        Locale result = parseLocaleString(localeString);
+        if (result == null) {
+            Log.w(TAG, "Failed to parse locale " + localeString + ", returning en_US instead");
+            result = Locale.US;
+        }
+
+        if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + result);
+
+        return result;
+    }
+
+
+    /**
      * True if a given TTS engine uses the default phone locale as a default locale. Attempts to
-     * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
-     * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
-     * both these values are empty, this methods returns true.
+     * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}. If
+     * its  value is empty, this methods returns true.
      *
      * @param engineName the engine to return the locale for.
      */
     public boolean isLocaleSetToDefaultForEngine(String engineName) {
-        return (TextUtils.isEmpty(parseEnginePrefFromList(
+        return TextUtils.isEmpty(parseEnginePrefFromList(
                     getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
-                    engineName)) &&
-                    TextUtils.isEmpty(
-                        Settings.Secure.getString(mContext.getContentResolver(),
-                        Settings.Secure.TTS_DEFAULT_LANG)));
+                    engineName));
     }
 
-
     /**
-     * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
-     * Varies from {@link String#split} in that it will always return an array
-     * of length 3 with non null values.
+     * Parses a locale encoded as a string, and tries its best to return a valid {@link Locale}
+     * object, even if the input string is encoded using the old-style 3 character format e.g.
+     * "deu-deu". At the end, we test if the resulting locale can return ISO3 language and
+     * country codes ({@link Locale#getISO3Language()} and {@link Locale#getISO3Country()}),
+     * if it fails to do so, we return null.
      */
-    public static String[] parseLocalePref(String pref) {
-        String[] returnVal = new String[] { "", "", ""};
-        if (!TextUtils.isEmpty(pref)) {
-            String[] split = pref.split(LOCALE_DELIMITER);
-            System.arraycopy(split, 0, returnVal, 0, split.length);
+    public Locale parseLocaleString(String localeString) {
+        String language = "", country = "", variant = "";
+        if (!TextUtils.isEmpty(localeString)) {
+            String[] split = localeString.split(
+                    "[" + LOCALE_DELIMITER_OLD + LOCALE_DELIMITER_NEW + "]");
+            language = split[0].toLowerCase();
+            if (split.length == 0) {
+                Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Only" +
+                            " separators");
+                return null;
+            }
+            if (split.length > 3) {
+                Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Too" +
+                        " many separators");
+                return null;
+            }
+            if (split.length >= 2) {
+                country = split[1].toUpperCase();
+            }
+            if (split.length >= 3) {
+                variant = split[2];
+            }
+
         }
 
-        if (DBG) Log.d(TAG, "parseLocalePref(" + returnVal[0] + "," + returnVal[1] +
-                "," + returnVal[2] +")");
+        String normalizedLanguage = sNormalizeLanguage.get(language);
+        if (normalizedLanguage != null) {
+            language = normalizedLanguage;
+        }
 
-        return returnVal;
+        String normalizedCountry= sNormalizeCountry.get(country);
+        if (normalizedCountry != null) {
+            country = normalizedCountry;
+        }
+
+        if (DBG) Log.d(TAG, "parseLocalePref(" + language + "," + country +
+                "," + variant +")");
+
+        Locale result = new Locale(language, country, variant);
+        try {
+            result.getISO3Language();
+            result.getISO3Country();
+            return result;
+        } catch(MissingResourceException e) {
+            Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object.");
+            return null;
+        }
     }
 
     /**
-     * @return the old style locale string constructed from
-     *         {@link Settings.Secure#TTS_DEFAULT_LANG},
-     *         {@link Settings.Secure#TTS_DEFAULT_COUNTRY} and
-     *         {@link Settings.Secure#TTS_DEFAULT_VARIANT}. If no such locale is set,
-     *         then return the default phone locale.
-     */
-    private String getV1Locale() {
-        final ContentResolver cr = mContext.getContentResolver();
-
-        final String lang = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_LANG);
-        final String country = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_COUNTRY);
-        final String variant = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_VARIANT);
-
-        if (TextUtils.isEmpty(lang)) {
-            return getDefaultLocale();
-        }
-
-        String v1Locale = lang;
-        if (!TextUtils.isEmpty(country)) {
-            v1Locale += LOCALE_DELIMITER + country;
-        } else {
-            return v1Locale;
-        }
-
-        if (!TextUtils.isEmpty(variant)) {
-            v1Locale += LOCALE_DELIMITER + variant;
-        }
-
-        return v1Locale;
-    }
-
-    /**
-     * Return the default device locale in form of 3 letter codes delimited by
-     * {@link #LOCALE_DELIMITER}:
+     * Return the old-style string form of the locale. It consists of 3 letter codes:
      * <ul>
-     *   <li> "ISO 639-2/T language code" if locale have no country entry</li>
-     *   <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code "
-     *     if locale have no variant entry</li>
-     *   <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code
-     *     {@link #LOCALE_DELIMITER} variant" if locale have variant entry</li>
+     *   <li>"ISO 639-2/T language code" if the locale has no country entry</li>
+     *   <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code"
+     *     if the locale has no variant entry</li>
+     *   <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country
+     *     code{@link #LOCALE_DELIMITER}variant" if the locale has a variant entry</li>
      * </ul>
+     * If we fail to generate those codes using {@link Locale#getISO3Country()} and
+     * {@link Locale#getISO3Language()}, then we return new String[]{"eng","USA",""};
      */
-    public String getDefaultLocale() {
-        final Locale locale = Locale.getDefault();
-
+    static public String[] toOldLocaleStringFormat(Locale locale) {
+        String[] ret = new String[]{"","",""};
         try {
             // Note that the default locale might have an empty variant
             // or language, and we take care that the construction is
             // the same as {@link #getV1Locale} i.e no trailing delimiters
             // or spaces.
-            String defaultLocale = locale.getISO3Language();
-            if (TextUtils.isEmpty(defaultLocale)) {
-                Log.w(TAG, "Default locale is empty.");
-                return "";
-            }
+            ret[0] = locale.getISO3Language();
+            ret[1] = locale.getISO3Country();
+            ret[2] = locale.getVariant();
 
-            if (!TextUtils.isEmpty(locale.getISO3Country())) {
-                defaultLocale += LOCALE_DELIMITER + locale.getISO3Country();
-            } else {
-                // Do not allow locales of the form lang--variant with
-                // an empty country.
-                return defaultLocale;
-            }
-            if (!TextUtils.isEmpty(locale.getVariant())) {
-                defaultLocale += LOCALE_DELIMITER + locale.getVariant();
-            }
-
-            return defaultLocale;
+            return ret;
         } catch (MissingResourceException e) {
             // Default locale does not have a ISO 3166 and/or ISO 639-2/T codes. Return the
             // default "eng-usa" (that would be the result of Locale.getDefault() == Locale.US).
-            return "eng-usa";
+            return new String[]{"eng","USA",""};
         }
     }
 
@@ -443,16 +482,21 @@
         return null;
     }
 
-    public synchronized void updateLocalePrefForEngine(String name, String newLocale) {
+    /**
+     * Serialize the locale to a string and store it as a default locale for the given engine. If
+     * the passed locale is null, an empty string will be serialized; that empty string, when
+     * read back, will evaluate to {@link Locale#getDefault()}.
+     */
+    public synchronized void updateLocalePrefForEngine(String engineName, Locale newLocale) {
         final String prefList = Settings.Secure.getString(mContext.getContentResolver(),
                 Settings.Secure.TTS_DEFAULT_LOCALE);
         if (DBG) {
-            Log.d(TAG, "updateLocalePrefForEngine(" + name + ", " + newLocale +
+            Log.d(TAG, "updateLocalePrefForEngine(" + engineName + ", " + newLocale +
                     "), originally: " + prefList);
         }
 
         final String newPrefList = updateValueInCommaSeparatedList(prefList,
-                name, newLocale);
+                engineName, (newLocale != null) ? newLocale.toString() : "");
 
         if (DBG) Log.d(TAG, "updateLocalePrefForEngine(), writing: " + newPrefList.toString());
 
diff --git a/core/java/android/speech/tts/VoiceInfo.java b/core/java/android/speech/tts/VoiceInfo.java
index 16b9a97..71629dc 100644
--- a/core/java/android/speech/tts/VoiceInfo.java
+++ b/core/java/android/speech/tts/VoiceInfo.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
 
 import android.os.Bundle;
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index d426d124..8674c66 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -38,7 +38,7 @@
      * {@hide}
      */
     void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, Paint p);
+            float x, float y, boolean isRtl, Paint p);
 
    /**
      * Just like {@link Paint#measureText}.
@@ -55,12 +55,12 @@
      * @hide
      */
     float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex, Paint paint);
+            boolean isRtl, float[] advances, int advancesIndex, Paint paint);
 
     /**
      * Just like {@link Paint#getTextRunCursor}.
      * @hide
      */
-    int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
+    int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset,
             int cursorOpt, Paint p);
 }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index f8e3c83..2415b11 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -159,18 +159,17 @@
         mPos = p + len;
 
         if (mEasy) {
-            int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
-                ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
-            return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
+            boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
+            return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
         }
 
         float totalAdvance = 0;
         int level = mLevels[p];
         for (int q = p, i = p + 1, e = p + len;; ++i) {
             if (i == e || mLevels[i] != level) {
-                int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
+                boolean isRtl = (level & 0x1) != 0;
                 totalAdvance +=
-                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
+                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
                 if (i == e) {
                     break;
                 }
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index f440853..6b984d6 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -440,26 +440,10 @@
     }
 
     // Documentation from interface
-    public SpannableStringBuilder replace(int start, int end,
+    public SpannableStringBuilder replace(final int start, final int end,
             CharSequence tb, int tbstart, int tbend) {
         checkRange("replace", start, end);
 
-        // Sanity check
-        if (start > end) {
-            Log.w(TAG, "Bad arguments to #replace : "
-                    + "start = " + start + ", end = " + end);
-            final int tmp = start;
-            start = end;
-            end = tmp;
-        }
-        if (tbstart > tbend) {
-            Log.w(TAG, "Bad arguments to #replace : "
-                    + "tbstart = " + tbstart + ", tbend = " + tbend);
-            final int tmp = tbstart;
-            tbstart = tbend;
-            tbend = tmp;
-        }
-
         int filtercount = mFilters.length;
         for (int i = 0; i < filtercount; i++) {
             CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -519,7 +503,7 @@
         // Span watchers need to be called after text watchers, which may update the layout
         sendToSpanWatchers(start, end, newLen - origLen);
 
-        return this; 
+        return this;
     }
 
     private static boolean hasNonExclusiveExclusiveSpanAt(CharSequence text, int offset) {
@@ -761,7 +745,7 @@
             }
         }
 
-        return 0; 
+        return 0;
     }
 
     /**
@@ -1133,20 +1117,20 @@
      * {@hide}
      */
     public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, Paint p) {
+            float x, float y, boolean isRtl, Paint p) {
         checkRange("drawTextRun", start, end);
 
         int contextLen = contextEnd - contextStart;
         int len = end - start;
         if (contextEnd <= mGapStart) {
-            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p);
+            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, isRtl, p);
         } else if (contextStart >= mGapStart) {
             c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
-                    contextLen, x, y, flags, p);
+                    contextLen, x, y, isRtl, p);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
-            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p);
+            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, isRtl, p);
             TextUtils.recycle(buf);
         }
     }
@@ -1203,7 +1187,7 @@
      * Don't call this yourself -- exists for Paint to use internally.
      * {@hide}
      */
-    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
+    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, boolean isRtl,
             float[] advances, int advancesPos, Paint p) {
 
         float ret;
@@ -1213,15 +1197,15 @@
 
         if (end <= mGapStart) {
             ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
-                    flags, advances, advancesPos);
+                    isRtl, advances, advancesPos);
         } else if (start >= mGapStart) {
             ret = p.getTextRunAdvances(mText, start + mGapLength, len,
-                    contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+                    contextStart + mGapLength, contextLen, isRtl, advances, advancesPos);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunAdvances(buf, start - contextStart, len,
-                    0, contextLen, flags, advances, advancesPos);
+                    0, contextLen, isRtl, advances, advancesPos);
             TextUtils.recycle(buf);
         }
 
@@ -1244,7 +1228,7 @@
      *
      * @param contextStart the start index of the context
      * @param contextEnd the (non-inclusive) end index of the context
-     * @param flags either DIRECTION_RTL or DIRECTION_LTR
+     * @param dir either DIRECTION_RTL or DIRECTION_LTR
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
      * CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@@ -1254,7 +1238,7 @@
      * @deprecated This is an internal method, refrain from using it in your code
      */
     @Deprecated
-    public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
+    public int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset,
             int cursorOpt, Paint p) {
 
         int ret;
@@ -1262,15 +1246,15 @@
         int contextLen = contextEnd - contextStart;
         if (contextEnd <= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart, contextLen,
-                    flags, offset, cursorOpt);
+                    dir, offset, cursorOpt);
         } else if (contextStart >= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
-                    flags, offset + mGapLength, cursorOpt) - mGapLength;
+                    dir, offset + mGapLength, cursorOpt) - mGapLength;
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunCursor(buf, 0, contextLen,
-                    flags, offset - contextStart, cursorOpt) + contextStart;
+                    dir, offset - contextStart, cursorOpt) + contextStart;
             TextUtils.recycle(buf);
         }
 
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index d892f19..c19cf32 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -664,14 +664,14 @@
             }
         }
 
-        int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
+        int dir = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
         int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
         if (mCharsValid) {
             return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
-                    flags, offset, cursorOpt);
+                    dir, offset, cursorOpt);
         } else {
             return wp.getTextRunCursor(mText, mStart + spanStart,
-                    mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
+                    mStart + spanLimit, dir, mStart + offset, cursorOpt) - mStart;
         }
     }
 
@@ -738,15 +738,14 @@
 
         int contextLen = contextEnd - contextStart;
         if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
-            int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
             if (mCharsValid) {
                 ret = wp.getTextRunAdvances(mChars, start, runLen,
-                        contextStart, contextLen, flags, null, 0);
+                        contextStart, contextLen, runIsRtl, null, 0);
             } else {
                 int delta = mStart;
                 ret = wp.getTextRunAdvances(mText, delta + start,
                         delta + end, delta + contextStart, delta + contextEnd,
-                        flags, null, 0);
+                        runIsRtl, null, 0);
             }
         }
 
@@ -977,16 +976,15 @@
     private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
             int contextStart, int contextEnd, boolean runIsRtl, float x, int y) {
 
-        int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
         if (mCharsValid) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start, count, contextStart, contextCount,
-                    x, y, flags, wp);
+                    x, y, runIsRtl, wp);
         } else {
             int delta = mStart;
             c.drawTextRun(mText, delta + start, delta + end,
-                    delta + contextStart, delta + contextEnd, x, y, flags, wp);
+                    delta + contextStart, delta + contextEnd, x, y, runIsRtl, wp);
         }
     }
 
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index d1f35dd..9fec9a1 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -195,7 +195,7 @@
      * @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
      */
     public static String getBestDateTimePattern(Locale locale, String skeleton) {
-        return ICU.getBestDateTimePattern(skeleton, locale.toString());
+        return ICU.getBestDateTimePattern(skeleton, locale);
     }
 
     /**
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index deb138d..c1341e1 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -465,32 +465,39 @@
         String address;
         int base = 0;
 
-        while ((address = WebView.findAddress(string)) != null) {
-            int start = string.indexOf(address);
+        try {
+            while ((address = WebView.findAddress(string)) != null) {
+                int start = string.indexOf(address);
 
-            if (start < 0) {
-                break;
+                if (start < 0) {
+                    break;
+                }
+
+                LinkSpec spec = new LinkSpec();
+                int length = address.length();
+                int end = start + length;
+
+                spec.start = base + start;
+                spec.end = base + end;
+                string = string.substring(end);
+                base += end;
+
+                String encodedAddress = null;
+
+                try {
+                    encodedAddress = URLEncoder.encode(address,"UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    continue;
+                }
+
+                spec.url = "geo:0,0?q=" + encodedAddress;
+                links.add(spec);
             }
-
-            LinkSpec spec = new LinkSpec();
-            int length = address.length();
-            int end = start + length;
-            
-            spec.start = base + start;
-            spec.end = base + end;
-            string = string.substring(end);
-            base += end;
-
-            String encodedAddress = null;
-
-            try {
-                encodedAddress = URLEncoder.encode(address,"UTF-8");
-            } catch (UnsupportedEncodingException e) {
-                continue;
-            }
-
-            spec.url = "geo:0,0?q=" + encodedAddress;
-            links.add(spec);
+        } catch (UnsupportedOperationException e) {
+            // findAddress may fail with an unsupported exception on platforms without a WebView.
+            // In this case, we will not append anything to the links variable: it would have died
+            // in WebView.findAddress.
+            return;
         }
     }
 
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index e9c2bba..508769d 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -206,6 +206,10 @@
     // like CircularPropagation
     EpicenterCallback mEpicenterCallback;
 
+    // For Fragment shared element transitions, linking views explicitly by mismatching
+    // viewNames.
+    ArrayMap<String, String> mNameOverrides;
+
     /**
      * Constructs a Transition object with no target objects. A transition with
      * no targets defaults to running on all target objects in the scene hierarchy
@@ -603,76 +607,76 @@
         for (int i = 0; i < startValuesList.size(); ++i) {
             TransitionValues start = startValuesList.get(i);
             TransitionValues end = endValuesList.get(i);
-            // Only bother trying to animate with values that differ between start/end
-            if (start != null || end != null) {
-                if (start == null || !start.equals(end)) {
-                    if (DBG) {
-                        View view = (end != null) ? end.view : start.view;
-                        Log.d(LOG_TAG, "  differing start/end values for view " +
-                                view);
-                        if (start == null || end == null) {
-                            Log.d(LOG_TAG, "    " + ((start == null) ?
-                                    "start null, end non-null" : "start non-null, end null"));
-                        } else {
-                            for (String key : start.values.keySet()) {
-                                Object startValue = start.values.get(key);
-                                Object endValue = end.values.get(key);
-                                if (startValue != endValue && !startValue.equals(endValue)) {
-                                    Log.d(LOG_TAG, "    " + key + ": start(" + startValue +
-                                            "), end(" + endValue +")");
-                                }
+            // Only bother trying to animate with valid values that differ between start/end
+            boolean isInvalidStart = start != null && !isValidTarget(start.view);
+            boolean isInvalidEnd = end != null && !isValidTarget(end.view);
+            boolean isChanged = start != end && (start == null || !start.equals(end));
+            if (isChanged && !isInvalidStart && !isInvalidEnd) {
+                if (DBG) {
+                    View view = (end != null) ? end.view : start.view;
+                    Log.d(LOG_TAG, "  differing start/end values for view " + view);
+                    if (start == null || end == null) {
+                        Log.d(LOG_TAG, "    " + ((start == null) ?
+                                "start null, end non-null" : "start non-null, end null"));
+                    } else {
+                        for (String key : start.values.keySet()) {
+                            Object startValue = start.values.get(key);
+                            Object endValue = end.values.get(key);
+                            if (startValue != endValue && !startValue.equals(endValue)) {
+                                Log.d(LOG_TAG, "    " + key + ": start(" + startValue +
+                                        "), end(" + endValue + ")");
                             }
                         }
                     }
-                    // TODO: what to do about targetIds and itemIds?
-                    Animator animator = createAnimator(sceneRoot, start, end);
+                }
+                // TODO: what to do about targetIds and itemIds?
+                Animator animator = createAnimator(sceneRoot, start, end);
+                if (animator != null) {
+                    // Save animation info for future cancellation purposes
+                    View view = null;
+                    TransitionValues infoValues = null;
+                    if (end != null) {
+                        view = end.view;
+                        String[] properties = getTransitionProperties();
+                        if (view != null && properties != null && properties.length > 0) {
+                            infoValues = new TransitionValues();
+                            infoValues.view = view;
+                            TransitionValues newValues = endValues.viewValues.get(view);
+                            if (newValues != null) {
+                                for (int j = 0; j < properties.length; ++j) {
+                                    infoValues.values.put(properties[j],
+                                            newValues.values.get(properties[j]));
+                                }
+                            }
+                            int numExistingAnims = runningAnimators.size();
+                            for (int j = 0; j < numExistingAnims; ++j) {
+                                Animator anim = runningAnimators.keyAt(j);
+                                AnimationInfo info = runningAnimators.get(anim);
+                                if (info.values != null && info.view == view &&
+                                        ((info.name == null && getName() == null) ||
+                                                info.name.equals(getName()))) {
+                                    if (info.values.equals(infoValues)) {
+                                        // Favor the old animator
+                                        animator = null;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    } else {
+                        view = (start != null) ? start.view : null;
+                    }
                     if (animator != null) {
-                        // Save animation info for future cancellation purposes
-                        View view = null;
-                        TransitionValues infoValues = null;
-                        if (end != null) {
-                            view = end.view;
-                            String[] properties = getTransitionProperties();
-                            if (view != null && properties != null && properties.length > 0) {
-                                infoValues = new TransitionValues();
-                                infoValues.view = view;
-                                TransitionValues newValues = endValues.viewValues.get(view);
-                                if (newValues != null) {
-                                    for (int j = 0; j < properties.length; ++j) {
-                                        infoValues.values.put(properties[j],
-                                                newValues.values.get(properties[j]));
-                                    }
-                                }
-                                int numExistingAnims = runningAnimators.size();
-                                for (int j = 0; j < numExistingAnims; ++j) {
-                                    Animator anim = runningAnimators.keyAt(j);
-                                    AnimationInfo info = runningAnimators.get(anim);
-                                    if (info.values != null && info.view == view &&
-                                            ((info.name == null && getName() == null) ||
-                                            info.name.equals(getName()))) {
-                                        if (info.values.equals(infoValues)) {
-                                            // Favor the old animator
-                                            animator = null;
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                        } else {
-                            view = (start != null) ? start.view : null;
+                        if (mPropagation != null) {
+                            long delay = mPropagation
+                                    .getStartDelay(sceneRoot, this, start, end);
+                            startDelays.put(mAnimators.size(), delay);
+                            minStartDelay = Math.min(delay, minStartDelay);
                         }
-                        if (animator != null) {
-                            if (mPropagation != null) {
-                                long delay = mPropagation
-                                        .getStartDelay(sceneRoot, this, start, end);
-                                startDelays.put(mAnimators.size(), delay);
-                                minStartDelay = Math.min(delay, minStartDelay);
-                            }
-                            AnimationInfo info = new AnimationInfo(view, getName(),
-                                    sceneRoot.getWindowId(), infoValues);
-                            runningAnimators.put(animator, info);
-                            mAnimators.add(animator);
-                        }
+                        AnimationInfo info = new AnimationInfo(view, getName(),
+                                sceneRoot.getWindowId(), infoValues);
+                        runningAnimators.put(animator, info);
+                        mAnimators.add(animator);
                     }
                 }
             }
@@ -1347,6 +1351,21 @@
         } else {
             captureHierarchy(sceneRoot, start);
         }
+        if (!start && mNameOverrides != null) {
+            int numOverrides = mNameOverrides.size();
+            ArrayList<View> overriddenViews = new ArrayList<View>(numOverrides);
+            for (int i = 0; i < numOverrides; i++) {
+                String fromName = mNameOverrides.keyAt(i);
+                overriddenViews.add(mStartValues.nameValues.remove(fromName));
+            }
+            for (int i = 0; i < numOverrides; i++) {
+                View view = overriddenViews.get(i);
+                if (view != null) {
+                    String toName = mNameOverrides.valueAt(i);
+                    mStartValues.nameValues.put(toName, view);
+                }
+            }
+        }
     }
 
     static void addViewValues(TransitionValuesMaps transitionValuesMaps,
@@ -1400,10 +1419,12 @@
             mStartValues.viewValues.clear();
             mStartValues.idValues.clear();
             mStartValues.itemIdValues.clear();
+            mStartValues.nameValues.clear();
         } else {
             mEndValues.viewValues.clear();
             mEndValues.idValues.clear();
             mEndValues.itemIdValues.clear();
+            mEndValues.nameValues.clear();
         }
     }
 
@@ -1866,6 +1887,20 @@
         return mCanRemoveViews;
     }
 
+    /**
+     * Sets the shared element names -- a mapping from a name at the start state to
+     * a different name at the end state.
+     * @hide
+     */
+    public void setNameOverrides(ArrayMap<String, String> overrides) {
+        mNameOverrides = overrides;
+    }
+
+    /** @hide */
+    public ArrayMap<String, String> getNameOverrides() {
+        return mNameOverrides;
+    }
+
     @Override
     public String toString() {
         return toString("");
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 698b563..c04be4f 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -168,30 +168,106 @@
 
     @Override
     public TransitionSet addTarget(View target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(target);
+        }
         return (TransitionSet) super.addTarget(target);
     }
 
     @Override
     public TransitionSet addTarget(int targetId) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(targetId);
+        }
         return (TransitionSet) super.addTarget(targetId);
     }
 
     @Override
+    public TransitionSet addTarget(String targetName) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(targetName);
+        }
+        return (TransitionSet) super.addTarget(targetName);
+    }
+
+    @Override
+    public TransitionSet addTarget(Class targetType) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).addTarget(targetType);
+        }
+        return (TransitionSet) super.addTarget(targetType);
+    }
+
+    @Override
     public TransitionSet addListener(TransitionListener listener) {
         return (TransitionSet) super.addListener(listener);
     }
 
     @Override
     public TransitionSet removeTarget(int targetId) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(targetId);
+        }
         return (TransitionSet) super.removeTarget(targetId);
     }
 
     @Override
     public TransitionSet removeTarget(View target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(target);
+        }
         return (TransitionSet) super.removeTarget(target);
     }
 
     @Override
+    public TransitionSet removeTarget(Class target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(target);
+        }
+        return (TransitionSet) super.removeTarget(target);
+    }
+
+    @Override
+    public TransitionSet removeTarget(String target) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).removeTarget(target);
+        }
+        return (TransitionSet) super.removeTarget(target);
+    }
+
+    @Override
+    public Transition excludeTarget(View target, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(target, exclude);
+        }
+        return super.excludeTarget(target, exclude);
+    }
+
+    @Override
+    public Transition excludeTarget(String targetViewName, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(targetViewName, exclude);
+        }
+        return super.excludeTarget(targetViewName, exclude);
+    }
+
+    @Override
+    public Transition excludeTarget(int targetId, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(targetId, exclude);
+        }
+        return super.excludeTarget(targetId, exclude);
+    }
+
+    @Override
+    public Transition excludeTarget(Class type, boolean exclude) {
+        for (int i = 0; i < mTransitions.size(); i++) {
+            mTransitions.get(i).excludeTarget(type, exclude);
+        }
+        return super.excludeTarget(type, exclude);
+    }
+
+    @Override
     public TransitionSet removeListener(TransitionListener listener) {
         return (TransitionSet) super.removeListener(listener);
     }
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 0f7638b..c6c8337 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -18,6 +18,9 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -272,15 +275,23 @@
                 if (startView.getParent() == null) {
                     // no parent - safe to use
                     overlayView = startView;
-                } else if (startView.getParent() instanceof View &&
-                        startView.getParent().getParent() == null) {
+                } else if (startView.getParent() instanceof View) {
                     View startParent = (View) startView.getParent();
-                    int id = startParent.getId();
-                    if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) {
-                        // no parent, but its parent is unparented  but the parent
-                        // hierarchy has been replaced by a new hierarchy with the same id
-                        // and it is safe to un-parent startView
-                        overlayView = startView;
+                    if (!isValidTarget(startParent)) {
+                        if (startView.isAttachedToWindow()) {
+                            overlayView = copyViewImage(startView);
+                        } else {
+                            overlayView = startView;
+                        }
+                    } else if (startParent.getParent() == null) {
+                        int id = startParent.getId();
+                        if (id != View.NO_ID && sceneRoot.findViewById(id) != null
+                                && mCanRemoveViews) {
+                            // no parent, but its parent is unparented  but the parent
+                            // hierarchy has been replaced by a new hierarchy with the same id
+                            // and it is safe to un-parent startView
+                            overlayView = startView;
+                        }
                     }
                 }
             }
@@ -378,6 +389,26 @@
         return null;
     }
 
+    private View copyViewImage(View view) {
+        int width = view.getWidth();
+        int height = view.getHeight();
+        if (width <= 0 || height <= 0) {
+            return null;
+        }
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        view.draw(canvas);
+        final BitmapDrawable drawable = new BitmapDrawable(bitmap);
+
+        View overlayView = new View(view.getContext());
+        overlayView.setBackground(drawable);
+        int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+        int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+        overlayView.measure(widthSpec, heightSpec);
+        overlayView.layout(0, 0, width, height);
+        return overlayView;
+    }
+
     /**
      * The default implementation of this method returns a null Animator. Subclasses should
      * override this method to make targets disappear with the desired transition. The
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 8f4b710..f7d2821 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -62,10 +62,7 @@
      */
     public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
         TimeZone best = null;
-
-        Resources r = Resources.getSystem();
-        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
-        Date d = new Date(when);
+        final Date d = new Date(when);
 
         TimeZone current = TimeZone.getDefault();
         String currentName = current.getID();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 5056097..446bbc9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -51,10 +51,10 @@
 
     private int mWidth;
     private int mHeight;
-    
+
     private float[] mPoint;
     private float[] mLine;
-    
+
     private Rect mClipBounds;
     private RectF mPathBounds;
 
@@ -167,7 +167,7 @@
 
         nSetViewport(mRenderer, width, height);
     }
-    
+
     private static native void nSetViewport(long renderer, int width, int height);
 
     @Override
@@ -208,22 +208,22 @@
 
     /**
      * Must match Caches::FlushMode values
-     * 
-     * @see #flushCaches(int) 
+     *
+     * @see #flushCaches(int)
      */
     static final int FLUSH_CACHES_LAYERS = 0;
-    
+
     /**
      * Must match Caches::FlushMode values
-     * 
-     * @see #flushCaches(int) 
+     *
+     * @see #flushCaches(int)
      */
     static final int FLUSH_CACHES_MODERATE = 1;
 
     /**
      * Must match Caches::FlushMode values
-     * 
-     * @see #flushCaches(int) 
+     *
+     * @see #flushCaches(int)
      */
     static final int FLUSH_CACHES_FULL = 2;
 
@@ -245,7 +245,7 @@
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
     ///////////////////////////////////////////////////////////////////////////
-    
+
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         layer.setLayerPaint(paint);
         nDrawLayer(mRenderer, layer.getLayer(), x, y);
@@ -298,7 +298,7 @@
     public boolean clipRect(float left, float top, float right, float bottom) {
         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
     }
-    
+
     private static native boolean nClipRect(long renderer, float left, float top,
             float right, float bottom, int op);
 
@@ -311,14 +311,14 @@
     public boolean clipRect(int left, int top, int right, int bottom) {
         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
     }
-    
+
     private static native boolean nClipRect(long renderer, int left, int top,
             int right, int bottom, int op);
 
     @Override
     public boolean clipRect(Rect rect) {
         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
-                Region.Op.INTERSECT.nativeInt);        
+                Region.Op.INTERSECT.nativeInt);
     }
 
     @Override
@@ -360,7 +360,7 @@
     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
         return nQuickReject(mRenderer, left, top, right, bottom);
     }
-    
+
     private static native boolean nQuickReject(long renderer, float left, float top,
             float right, float bottom);
 
@@ -385,7 +385,7 @@
     public void translate(float dx, float dy) {
         if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
     }
-    
+
     private static native void nTranslate(long renderer, float dx, float dy);
 
     @Override
@@ -399,21 +399,24 @@
     public void rotate(float degrees) {
         nRotate(mRenderer, degrees);
     }
-    
+
     private static native void nRotate(long renderer, float degrees);
 
     @Override
     public void scale(float sx, float sy) {
+        // TODO: remove
+        if (sx > 1000000 || sy > 1000000) throw new IllegalArgumentException("invalid scales passed " + sx + ", " + sy);
+
         nScale(mRenderer, sx, sy);
     }
-    
+
     private static native void nScale(long renderer, float sx, float sy);
 
     @Override
     public void setMatrix(Matrix matrix) {
         nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
     }
-    
+
     private static native void nSetMatrix(long renderer, long matrix);
 
     @SuppressWarnings("deprecation")
@@ -421,16 +424,16 @@
     public void getMatrix(Matrix matrix) {
         nGetMatrix(mRenderer, matrix.native_instance);
     }
-    
+
     private static native void nGetMatrix(long renderer, long matrix);
 
     @Override
     public void concat(Matrix matrix) {
         if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance);
     }
-    
+
     private static native void nConcatMatrix(long renderer, long matrix);
-    
+
     ///////////////////////////////////////////////////////////////////////////
     // State management
     ///////////////////////////////////////////////////////////////////////////
@@ -439,14 +442,14 @@
     public int save() {
         return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
     }
-    
+
     @Override
     public int save(int saveFlags) {
         return nSave(mRenderer, saveFlags);
     }
 
     private static native int nSave(long renderer, int flags);
-    
+
     @Override
     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
         if (bounds != null) {
@@ -494,12 +497,12 @@
 
     private static native int nSaveLayerAlpha(long renderer, float left, float top, float right,
             float bottom, int alpha, int saveFlags);
-    
+
     @Override
     public void restore() {
         nRestore(mRenderer);
     }
-    
+
     private static native void nRestore(long renderer);
 
     @Override
@@ -508,12 +511,12 @@
     }
 
     private static native void nRestoreToCount(long renderer, int saveCount);
-    
+
     @Override
     public int getSaveCount() {
         return nGetSaveCount(mRenderer);
     }
-    
+
     private static native int nGetSaveCount(long renderer);
 
     ///////////////////////////////////////////////////////////////////////////
@@ -544,9 +547,9 @@
     ///////////////////////////////////////////////////////////////////////////
 
     @Override
-    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
-            Paint paint) {
-        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+    public void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
+        nDrawArc(mRenderer, left, top, right, bottom,
                 startAngle, sweepAngle, useCenter, paint.mNativePaint);
     }
 
@@ -739,7 +742,7 @@
     public void drawColor(int color, PorterDuff.Mode mode) {
         nDrawColor(mRenderer, color, mode.nativeInt);
     }
-    
+
     private static native void nDrawColor(long renderer, int color, int mode);
 
     @Override
@@ -771,8 +774,8 @@
     }
 
     @Override
-    public void drawOval(RectF oval, Paint paint) {
-        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+    public void drawOval(float left, float top, float right, float bottom, Paint paint) {
+        nDrawOval(mRenderer, left, top, right, bottom, paint.mNativePaint);
     }
 
     private static native void nDrawOval(long renderer, float left, float top,
@@ -930,7 +933,7 @@
         nDrawText(mRenderer, text, index, count, x, y,
                 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
-    
+
     private static native void nDrawText(long renderer, char[] text, int index, int count,
             float x, float y, int bidiFlags, long paint, long typeface);
 
@@ -997,49 +1000,45 @@
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, int dir, Paint paint) {
+            float x, float y, boolean isRtl, Paint paint) {
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
-            throw new IllegalArgumentException("Unknown direction: " + dir);
-        }
 
-        nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
+        nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, isRtl,
                 paint.mNativePaint, paint.mNativeTypeface);
     }
 
     private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
-            int contextIndex, int contextCount, float x, float y, int dir, long nativePaint, long nativeTypeface);
+            int contextIndex, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, int dir, Paint paint) {
+            float x, float y, boolean isRtl, Paint paint) {
         if ((start | end | end - start | text.length() - end) < 0) {
             throw new IndexOutOfBoundsException();
         }
 
-        int flags = dir == 0 ? 0 : 1;
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
-                    contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+                    contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
-                    contextStart, contextEnd, x, y, flags, paint);
+                    contextStart, contextEnd, x, y, isRtl, paint);
         } else {
             int contextLen = contextEnd - contextStart;
             int len = end - start;
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
-                    x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+                    x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
 
     private static native void nDrawTextRun(long renderer, String text, int start, int end,
-            int contextStart, int contextEnd, float x, float y, int flags, long nativePaint, long nativeTypeface);
+            int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
 
     @Override
     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index b5b9199..266a6fed 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -19,7 +19,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 
 import com.android.internal.util.VirtualRefBasePtr;
@@ -34,34 +33,18 @@
  * @hide
  */
 final class HardwareLayer {
-    private static final int LAYER_TYPE_TEXTURE = 1;
-    private static final int LAYER_TYPE_DISPLAY_LIST = 2;
-
     private HardwareRenderer mRenderer;
     private VirtualRefBasePtr mFinalizer;
-    private RenderNode mDisplayList;
-    private final int mLayerType;
 
-    private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+    private HardwareLayer(HardwareRenderer renderer, long deferredUpdater) {
         if (renderer == null || deferredUpdater == 0) {
             throw new IllegalArgumentException("Either hardware renderer: " + renderer
                     + " or deferredUpdater: " + deferredUpdater + " is invalid");
         }
         mRenderer = renderer;
-        mLayerType = type;
         mFinalizer = new VirtualRefBasePtr(deferredUpdater);
     }
 
-    private void assertType(int type) {
-        if (mLayerType != type) {
-            throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
-        }
-    }
-
-    boolean hasDisplayList() {
-        return mDisplayList != null;
-    }
-
     /**
      * Update the paint used when drawing this layer.
      *
@@ -90,11 +73,6 @@
             // Already destroyed
             return;
         }
-
-        if (mDisplayList != null) {
-            mDisplayList.destroyDisplayListData();
-            mDisplayList = null;
-        }
         mRenderer.onLayerDestroyed(this);
         mRenderer = null;
         mFinalizer.release();
@@ -105,21 +83,6 @@
         return mFinalizer.get();
     }
 
-    public RenderNode startRecording() {
-        assertType(LAYER_TYPE_DISPLAY_LIST);
-
-        if (mDisplayList == null) {
-            mDisplayList = RenderNode.create("HardwareLayer");
-        }
-        return mDisplayList;
-    }
-
-    public void endRecording(Rect dirtyRect) {
-        nUpdateRenderLayer(mFinalizer.get(), mDisplayList.getNativeDisplayList(),
-                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
-        mRenderer.pushLayerUpdate(this);
-    }
-
     /**
      * Copies this layer into the specified bitmap.
      *
@@ -160,7 +123,6 @@
      * Indicates that this layer has lost its texture.
      */
     public void detachSurfaceTexture(final SurfaceTexture surface) {
-        assertType(LAYER_TYPE_TEXTURE);
         mRenderer.safelyRun(new Runnable() {
             @Override
             public void run() {
@@ -177,13 +139,11 @@
     }
 
     public void setSurfaceTexture(SurfaceTexture surface) {
-        assertType(LAYER_TYPE_TEXTURE);
         nSetSurfaceTexture(mFinalizer.get(), surface, false);
         mRenderer.pushLayerUpdate(this);
     }
 
     public void updateSurfaceTexture() {
-        assertType(LAYER_TYPE_TEXTURE);
         nUpdateSurfaceTexture(mFinalizer.get());
         mRenderer.pushLayerUpdate(this);
     }
@@ -192,18 +152,13 @@
      * This should only be used by HardwareRenderer! Do not call directly
      */
     SurfaceTexture createSurfaceTexture() {
-        assertType(LAYER_TYPE_TEXTURE);
         SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.get()));
         nSetSurfaceTexture(mFinalizer.get(), st, true);
         return st;
     }
 
     static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
-        return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
-    }
-
-    static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
-        return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
+        return new HardwareLayer(renderer, layer);
     }
 
     private static native void nOnTextureDestroyed(long layerUpdater);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 592dec8..c0e42a3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -374,16 +375,6 @@
     abstract HardwareLayer createTextureLayer();
 
     /**
-     * Creates a new hardware layer.
-     *
-     * @param width The minimum width of the layer
-     * @param height The minimum height of the layer
-     *
-     * @return A hardware layer
-     */
-    abstract HardwareLayer createDisplayListLayer(int width, int height);
-
-    /**
      * Creates a new {@link SurfaceTexture} that can be used to render into the
      * specified hardware layer.
      *
@@ -462,10 +453,10 @@
      *
      * @return A hardware renderer backed by OpenGL.
      */
-    static HardwareRenderer create(boolean translucent) {
+    static HardwareRenderer create(Context context, boolean translucent) {
         HardwareRenderer renderer = null;
         if (GLES20Canvas.isAvailable()) {
-            renderer = new ThreadedRenderer(translucent);
+            renderer = new ThreadedRenderer(context, translucent);
         }
         return renderer;
     }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index c32a2c9..fa5bd88 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -46,7 +46,7 @@
     int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             in int viewVisibility, in int layerStackId, out Rect outContentInsets);
     void remove(IWindow window);
-    
+
     /**
      * Change the parameters of a window.  You supply the
      * new parameters, it returns the new frame of the window on screen (the
@@ -109,7 +109,7 @@
      * to optimize compositing of this part of the window.
      */
     void setTransparentRegion(IWindow window, in Region region);
-    
+
     /**
      * Tell the window manager about the content and visible insets of the
      * given window, which can be used to adjust the <var>outContentInsets</var>
@@ -122,20 +122,20 @@
      */
     void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
             in Rect visibleInsets, in Region touchableRegion);
-    
+
     /**
      * Return the current display size in which the window is being laid out,
      * accounting for screen decorations around it.
      */
     void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
-    
+
     void finishDrawing(IWindow window);
-    
+
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
-    
+
     boolean performHapticFeedback(IWindow window, int effectId, boolean always);
-    
+
     /**
      * Allocate the drag's thumbnail surface.  Also assigns a token that identifies
      * the drag to the OS and passes that as the return value.  A return value of
@@ -150,11 +150,11 @@
     boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
             float thumbCenterX, float thumbCenterY, in ClipData data);
 
-	/**
-	 * Report the result of a drop action targeted to the given window.
-	 * consumed is 'true' when the drop was accepted by a valid recipient,
-	 * 'false' otherwise.
-	 */
+   /**
+     * Report the result of a drop action targeted to the given window.
+     * consumed is 'true' when the drop was accepted by a valid recipient,
+     * 'false' otherwise.
+     */
 	void reportDropResult(IWindow window, boolean consumed);
 
     /**
@@ -174,12 +174,12 @@
      * how big the increment is from one screen to another.
      */
     void setWallpaperPosition(IBinder windowToken, float x, float y, float xstep, float ystep);
-    
+
     void wallpaperOffsetsComplete(IBinder window);
-    
+
     Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, in Bundle extras, boolean sync);
-    
+
     void wallpaperCommandComplete(IBinder window, in Bundle result);
 
     void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
@@ -188,7 +188,7 @@
     /**
      * Notifies that a rectangle on the screen has been requested.
      */
-    void onRectangleOnScreenRequested(IBinder token, in Rect rectangle, boolean immediate);
+    void onRectangleOnScreenRequested(IBinder token, in Rect rectangle);
 
     IWindowId getWindowId(IBinder window);
 }
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 4631b64..d86b699 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.graphics.Matrix;
 import android.graphics.Outline;
+import android.graphics.Paint;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -322,11 +323,13 @@
      * handled in the drawLayer operation directly (and more efficiently).
      *
      * @param caching true if the display list represents a hardware layer, false otherwise.
-     *
-     * @hide
      */
-    public boolean setCaching(boolean caching) {
-        return nSetCaching(mNativeRenderNode, caching);
+    public boolean setLayerType(int layerType) {
+        return nSetLayerType(mNativeRenderNode, layerType);
+    }
+
+    public boolean setLayerPaint(Paint paint) {
+        return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
     }
 
     /**
@@ -842,13 +845,6 @@
     }
 
     /**
-     * Sets the scroll position, this is used for damage calculations
-     */
-    public void setScrollPosition(int x, int y) {
-        nSetScrollPosition(mNativeRenderNode, x, y);
-    }
-
-    /**
      * Outputs the display list to the log. This method exists for use by
      * tools to output display lists for selected nodes to the log.
      *
@@ -906,11 +902,11 @@
     private static native boolean nSetRight(long renderNode, int right);
     private static native boolean nSetTop(long renderNode, int top);
     private static native boolean nSetLeft(long renderNode, int left);
-    private static native void nSetScrollPosition(long renderNode, int scrollX, int scrollY);
     private static native boolean nSetCameraDistance(long renderNode, float distance);
     private static native boolean nSetPivotY(long renderNode, float pivotY);
     private static native boolean nSetPivotX(long renderNode, float pivotX);
-    private static native boolean nSetCaching(long renderNode, boolean caching);
+    private static native boolean nSetLayerType(long renderNode, int layerType);
+    private static native boolean nSetLayerPaint(long renderNode, long paint);
     private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
     private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
     private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5cd3d62..79f19b5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -78,8 +78,8 @@
             IBinder displayToken);
     private static native int nativeGetActiveConfig(IBinder displayToken);
     private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
-    private static native void nativeBlankDisplay(IBinder displayToken);
-    private static native void nativeUnblankDisplay(IBinder displayToken);
+    private static native void nativeSetDisplayPowerMode(
+            IBinder displayToken, int mode);
 
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -209,6 +209,25 @@
      */
     public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
 
+    /* Display power modes * /
+
+    /**
+     * Display power mode off: used while blanking the screen.
+     * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+     */
+    public static final int POWER_MODE_OFF = 0;
+
+    /**
+     * Display power mode doze: used while putting the screen into low power mode.
+     * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+     */
+    public static final int POWER_MODE_DOZE = 1;
+
+    /**
+     * Display power mode normal: used while unblanking the screen.
+     * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+     */
+    public static final int POWER_MODE_NORMAL = 2;
 
 
     /**
@@ -487,18 +506,11 @@
         }
     }
 
-    public static void unblankDisplay(IBinder displayToken) {
+    public static void setDisplayPowerMode(IBinder displayToken, int mode) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
-        nativeUnblankDisplay(displayToken);
-    }
-
-    public static void blankDisplay(IBinder displayToken) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        nativeBlankDisplay(displayToken);
+        nativeSetDisplayPowerMode(displayToken, mode);
     }
 
     public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 2a9f7d5..1f7eaa2 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -275,6 +275,11 @@
         }
     }
 
+    @Override
+    public void setLayerPaint(Paint paint) {
+        setLayerType(/* ignored */ 0, paint);
+    }
+
     /**
      * Always returns {@link #LAYER_TYPE_HARDWARE}.
      */
@@ -332,11 +337,6 @@
         }
     }
 
-    @Override
-    boolean destroyLayer(boolean valid) {
-        return false;
-    }
-
     /**
      * @hide
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7bbe84e..166edc2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,21 +16,29 @@
 
 package android.view;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
+import android.graphics.drawable.Drawable;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.TimeUtils;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
 
 /**
  * Hardware renderer that proxies the rendering to a render thread. Most calls
@@ -71,8 +79,8 @@
     private Choreographer mChoreographer;
     private boolean mProfilingEnabled;
 
-    ThreadedRenderer(boolean translucent) {
-        AtlasInitializer.sInstance.init();
+    ThreadedRenderer(Context context, boolean translucent) {
+        AtlasInitializer.sInstance.init(context);
 
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
@@ -257,12 +265,6 @@
     }
 
     @Override
-    HardwareLayer createDisplayListLayer(int width, int height) {
-        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
-        return HardwareLayer.adoptDisplayListLayer(this, layer);
-    }
-
-    @Override
     HardwareLayer createTextureLayer() {
         long layer = nCreateTextureLayer(mNativeProxy);
         return HardwareLayer.adoptTextureLayer(this, layer);
@@ -340,7 +342,7 @@
 
         private AtlasInitializer() {}
 
-        synchronized void init() {
+        synchronized void init(Context context) {
             if (mInitialized) return;
             IBinder binder = ServiceManager.getService("assetatlas");
             if (binder == null) return;
@@ -352,6 +354,8 @@
                     if (buffer != null) {
                         long[] map = atlas.getMap();
                         if (map != null) {
+                            // TODO Remove after fixing b/15425820
+                            validateMap(context, map);
                             nSetAtlas(buffer, map);
                             mInitialized = true;
                         }
@@ -367,6 +371,30 @@
                 Log.w(LOG_TAG, "Could not acquire atlas", e);
             }
         }
+
+        private static void validateMap(Context context, long[] map) {
+            Log.d("Atlas", "Validating map...");
+            HashSet<Long> preloadedPointers = new HashSet<Long>();
+
+            // We only care about drawables that hold bitmaps
+            final Resources resources = context.getResources();
+            final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
+
+            final int count = drawables.size();
+            for (int i = 0; i < count; i++) {
+                final Bitmap bitmap = drawables.valueAt(i).getBitmap();
+                if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
+                    preloadedPointers.add(bitmap.mNativeBitmap);
+                }
+            }
+
+            for (int i = 0; i < map.length; i += 4) {
+                if (!preloadedPointers.contains(map[i])) {
+                    Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
+                    map[i] = 0;
+                }
+            }
+        }
     }
 
     static native void setupShadersDiskCache(String cacheFile);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 65b1f8c..9156216 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25,6 +25,7 @@
 import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -44,6 +45,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
@@ -90,6 +92,7 @@
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -2775,6 +2778,13 @@
     /**
      * @hide
      *
+     * Whether Recents is visible or not.
+     */
+    public static final int RECENT_APPS_VISIBLE = 0x00004000;
+
+    /**
+     * @hide
+     *
      * Makes system ui transparent.
      */
     public static final int SYSTEM_UI_TRANSPARENT = 0x00008000;
@@ -2782,7 +2792,7 @@
     /**
      * @hide
      */
-    public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00007FFF;
+    public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FFF;
 
     /**
      * These are the system UI flags that can be cleared by events outside
@@ -3179,6 +3189,9 @@
 
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
     private Drawable mBackground;
+    private ColorStateList mBackgroundTint = null;
+    private PorterDuff.Mode mBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasBackgroundTint = false;
 
     /**
      * Display list used for backgrounds.
@@ -3465,8 +3478,6 @@
     })
     int mLayerType = LAYER_TYPE_NONE;
     Paint mLayerPaint;
-    Rect mLocalDirtyRect;
-    private HardwareLayer mHardwareLayer;
 
     /**
      * Set to true when drawing cache is enabled and cannot be created.
@@ -4016,6 +4027,16 @@
                     setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
                             a.getResourceId(attr, 0)));
                     break;
+                case R.styleable.View_backgroundTint:
+                    // This will get applied later during setBackground().
+                    mBackgroundTint = a.getColorStateList(R.styleable.View_backgroundTint);
+                    mHasBackgroundTint = true;
+                    break;
+                case R.styleable.View_backgroundTintMode:
+                    // This will get applied later during setBackground().
+                    mBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+                            R.styleable.View_backgroundTintMode, -1), mBackgroundTintMode);
+                    break;
             }
         }
 
@@ -4789,14 +4810,10 @@
      * @param v previous or the next focus holder, or null if none
      */
     private void manageFocusHotspot(boolean focused, View v) {
-        if (mBackground == null) {
-            return;
-        }
-
         final Rect r = new Rect();
-        if (!focused && v != null) {
+        if (!focused && v != null && mAttachInfo != null) {
             v.getBoundsOnScreen(r);
-            final int[] location = new int[2];
+            final int[] location = mAttachInfo.mTmpLocation;
             getLocationOnScreen(location);
             r.offset(-location[0], -location[1]);
         } else {
@@ -4805,7 +4822,20 @@
 
         final float x = r.exactCenterX();
         final float y = r.exactCenterY();
-        mBackground.setHotspot(x, y);
+        setDrawableHotspot(x, y);
+    }
+
+    /**
+     * Sets the hotspot position for this View's drawables.
+     *
+     * @param x hotspot x coordinate
+     * @param y hotspot y coordinate
+     * @hide
+     */
+    protected void setDrawableHotspot(float x, float y) {
+        if (mBackground != null) {
+            mBackground.setHotspot(x, y);
+        }
     }
 
     /**
@@ -6101,12 +6131,18 @@
      */
     protected boolean fitSystemWindows(Rect insets) {
         if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+            if (insets == null) {
+                // Null insets by definition have already been consumed.
+                // This call cannot apply insets since there are none to apply,
+                // so return false.
+                return false;
+            }
             // If we're not in the process of dispatching the newer apply insets call,
             // that means we're not in the compatibility path. Dispatch into the newer
             // apply insets path and take things from there.
             try {
                 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
-                return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+                return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed();
             } finally {
                 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS;
             }
@@ -6762,7 +6798,7 @@
      */
     private void setPressed(boolean pressed, float x, float y) {
         if (pressed) {
-            setHotspot(x, y);
+            setDrawableHotspot(x, y);
         }
 
         setPressed(pressed);
@@ -9101,8 +9137,7 @@
                         postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                     } else {
                         // Not inside a scrolling container, so show the feedback right away
-                        setHotspot(x, y);
-                        setPressed(true);
+                        setPressed(true, x, y);
                         checkForLongClick(0);
                     }
                     break;
@@ -9114,7 +9149,7 @@
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    setHotspot(x, y);
+                    setDrawableHotspot(x, y);
 
                     // Be lenient about moving outside of buttons
                     if (!pointInView(x, y, mTouchSlop)) {
@@ -9136,12 +9171,6 @@
         return false;
     }
 
-    private void setHotspot(float x, float y) {
-        if (mBackground != null) {
-            mBackground.setHotspot(x, y);
-        }
-    }
-
     /**
      * @hide
      */
@@ -12931,7 +12960,6 @@
         stopNestedScroll();
 
         destroyDrawingCache();
-        destroyLayer(false);
 
         cleanupDraw();
         mCurrentAnimation = null;
@@ -13409,28 +13437,25 @@
                     + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
         }
 
-        if (layerType == mLayerType) {
+        boolean typeChanged = mRenderNode.setLayerType(layerType);
+
+        if (!typeChanged) {
             setLayerPaint(paint);
             return;
         }
 
         // Destroy any previous software drawing cache if needed
-        switch (mLayerType) {
-            case LAYER_TYPE_HARDWARE:
-                destroyLayer(false);
-                // fall through - non-accelerated views may use software layer mechanism instead
-            case LAYER_TYPE_SOFTWARE:
-                destroyDrawingCache();
-                break;
-            default:
-                break;
+        if (mLayerType == LAYER_TYPE_SOFTWARE) {
+            destroyDrawingCache();
         }
 
         mLayerType = layerType;
-        final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
+        final boolean layerDisabled = (mLayerType == LAYER_TYPE_NONE);
         mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
-        mLocalDirtyRect = layerDisabled ? null : new Rect();
+        mRenderNode.setLayerPaint(mLayerPaint);
 
+        // draw() behaves differently if we are on a layer, so we need to
+        // invalidate() here
         invalidateParentCaches();
         invalidate(true);
     }
@@ -13465,11 +13490,9 @@
         if (layerType != LAYER_TYPE_NONE) {
             mLayerPaint = paint == null ? new Paint() : paint;
             if (layerType == LAYER_TYPE_HARDWARE) {
-                HardwareLayer layer = getHardwareLayer();
-                if (layer != null) {
-                    layer.setLayerPaint(mLayerPaint);
+                if (mRenderNode.setLayerPaint(mLayerPaint)) {
+                    invalidateViewProperty(false, false);
                 }
-                invalidateViewProperty(false, false);
             } else {
                 invalidate();
             }
@@ -13525,18 +13548,17 @@
             throw new IllegalStateException("This view must be attached to a window first");
         }
 
+        if (getWidth() == 0 || getHeight() == 0) {
+            return;
+        }
+
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                getHardwareLayer();
-                // TODO: We need a better way to handle this case
-                // If views have registered pre-draw listeners they need
-                // to be notified before we build the layer. Those listeners
-                // may however rely on other events to happen first so we
-                // cannot just invoke them here until they don't cancel the
-                // current frame
-                if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
-                    attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
-                }
+                // The only part of a hardware layer we can build in response to
+                // this call is to ensure the display list is up to date.
+                // The actual rendering of the display list into the layer must
+                // be done at playback time
+                updateDisplayListIfDirty();
                 break;
             case LAYER_TYPE_SOFTWARE:
                 buildDrawingCache(true);
@@ -13545,70 +13567,13 @@
     }
 
     /**
-     * <p>Returns a hardware layer that can be used to draw this view again
-     * without executing its draw method.</p>
+     * If this View draws with a HardwareLayer, returns it.
+     * Otherwise returns null
      *
-     * @return A HardwareLayer ready to render, or null if an error occurred.
+     * TODO: Only TextureView uses this, can we eliminate it?
      */
     HardwareLayer getHardwareLayer() {
-        if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null ||
-                !mAttachInfo.mHardwareRenderer.isEnabled()) {
-            return null;
-        }
-
-        final int width = mRight - mLeft;
-        final int height = mBottom - mTop;
-
-        if (width == 0 || height == 0) {
-            return null;
-        }
-
-        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
-            if (mHardwareLayer == null) {
-                mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
-                        width, height);
-                mLocalDirtyRect.set(0, 0, width, height);
-            } else if (mHardwareLayer.isValid()) {
-                // This should not be necessary but applications that change
-                // the parameters of their background drawable without calling
-                // this.setBackground(Drawable) can leave the view in a bad state
-                // (for instance isOpaque() returns true, but the background is
-                // not opaque.)
-                computeOpaqueFlags();
-
-                if (mHardwareLayer.prepare(width, height, isOpaque())) {
-                    mLocalDirtyRect.set(0, 0, width, height);
-                }
-            }
-
-            mHardwareLayer.setLayerPaint(mLayerPaint);
-            RenderNode displayList = mHardwareLayer.startRecording();
-            updateDisplayListIfDirty(displayList, true);
-            mHardwareLayer.endRecording(mLocalDirtyRect);
-            mLocalDirtyRect.setEmpty();
-        }
-
-        return mHardwareLayer;
-    }
-
-    /**
-     * Destroys this View's hardware layer if possible.
-     *
-     * @return True if the layer was destroyed, false otherwise.
-     *
-     * @see #setLayerType(int, android.graphics.Paint)
-     * @see #LAYER_TYPE_HARDWARE
-     */
-    boolean destroyLayer(boolean valid) {
-        if (mHardwareLayer != null) {
-            mHardwareLayer.destroy();
-            mHardwareLayer = null;
-
-            invalidate(true);
-            invalidateParentCaches();
-            return true;
-        }
-        return false;
+        return null;
     }
 
     /**
@@ -13624,7 +13589,6 @@
      */
     protected void destroyHardwareResources() {
         resetDisplayList();
-        destroyLayer(true);
     }
 
     /**
@@ -13719,33 +13683,19 @@
         return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null);
     }
 
-    /**
-     * Returns a DisplayList. If the incoming displayList is null, one will be created.
-     * Otherwise, the same display list will be returned (after having been rendered into
-     * along the way, depending on the invalidation state of the view).
-     *
-     * @param renderNode The previous version of this displayList, could be null.
-     * @param isLayer Whether the requester of the display list is a layer. If so,
-     * the view will avoid creating a layer inside the resulting display list.
-     * @return A new or reused DisplayList object.
-     */
-    private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
-        if (renderNode == null) {
-            throw new IllegalArgumentException("RenderNode must not be null");
-        }
+    private void updateDisplayListIfDirty() {
+        final RenderNode renderNode = mRenderNode;
         if (!canHaveDisplayList()) {
             // can't populate RenderNode, don't try
             return;
         }
 
-        renderNode.setScrollPosition(mScrollX, mScrollY);
         if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
                 || !renderNode.isValid()
-                || (!isLayer && mRecreateDisplayList)) {
+                || (mRecreateDisplayList)) {
             // Don't need to recreate the display list, just need to tell our
             // children to restore/recreate theirs
             if (renderNode.isValid()
-                    && !isLayer
                     && !mRecreateDisplayList) {
                 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
                 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
@@ -13754,13 +13704,10 @@
                 return; // no work needed
             }
 
-            if (!isLayer) {
-                // If we got here, we're recreating it. Mark it as such to ensure that
-                // we copy in child display lists into ours in drawChild()
-                mRecreateDisplayList = true;
-            }
+            // If we got here, we're recreating it. Mark it as such to ensure that
+            // we copy in child display lists into ours in drawChild()
+            mRecreateDisplayList = true;
 
-            boolean caching = false;
             int width = mRight - mLeft;
             int height = mBottom - mTop;
             int layerType = getLayerType();
@@ -13768,34 +13715,21 @@
             final HardwareCanvas canvas = renderNode.start(width, height);
 
             try {
-                if (!isLayer && layerType != LAYER_TYPE_NONE) {
-                    if (layerType == LAYER_TYPE_HARDWARE) {
-                        final HardwareLayer layer = getHardwareLayer();
-                        if (layer != null && layer.isValid()) {
-                            canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
-                        } else {
-                            canvas.saveLayer(0, 0, mRight - mLeft, mBottom - mTop, mLayerPaint,
-                                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
-                                            Canvas.CLIP_TO_LAYER_SAVE_FLAG);
-                        }
-                        caching = true;
-                    } else {
-                        buildDrawingCache(true);
-                        Bitmap cache = getDrawingCache(true);
-                        if (cache != null) {
-                            canvas.drawBitmap(cache, 0, 0, mLayerPaint);
-                            caching = true;
-                        }
+                final HardwareLayer layer = getHardwareLayer();
+                if (layer != null && layer.isValid()) {
+                    canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
+                } else if (layerType == LAYER_TYPE_SOFTWARE) {
+                    buildDrawingCache(true);
+                    Bitmap cache = getDrawingCache(true);
+                    if (cache != null) {
+                        canvas.drawBitmap(cache, 0, 0, mLayerPaint);
                     }
                 } else {
-
                     computeScroll();
 
                     canvas.translate(-mScrollX, -mScrollY);
-                    if (!isLayer) {
-                        mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
-                        mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-                    }
+                    mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+                    mPrivateFlags &= ~PFLAG_DIRTY_MASK;
 
                     // Fast path for layouts with no backgrounds
                     if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
@@ -13809,14 +13743,9 @@
                 }
             } finally {
                 renderNode.end(canvas);
-                renderNode.setCaching(caching);
-                if (isLayer) {
-                    renderNode.setLeftTopRightBottom(0, 0, width, height);
-                } else {
-                    setDisplayListProperties(renderNode);
-                }
+                setDisplayListProperties(renderNode);
             }
-        } else if (!isLayer) {
+        } else {
             mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
             mPrivateFlags &= ~PFLAG_DIRTY_MASK;
         }
@@ -13831,7 +13760,7 @@
      * @hide
      */
     public RenderNode getDisplayList() {
-        updateDisplayListIfDirty(mRenderNode, false);
+        updateDisplayListIfDirty();
         return mRenderNode;
     }
 
@@ -15784,7 +15713,7 @@
             return;
         }
 
-        Drawable d= null;
+        Drawable d = null;
         if (resid != 0) {
             d = mContext.getDrawable(resid);
         }
@@ -15860,8 +15789,9 @@
 
             // Compare the minimum sizes of the old Drawable and the new.  If there isn't an old or
             // if it has a different minimum size, we should layout again
-            if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
-                    mBackground.getMinimumWidth() != background.getMinimumWidth()) {
+            if (mBackground == null
+                    || mBackground.getMinimumHeight() != background.getMinimumHeight()
+                    || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
                 requestLayout = true;
             }
 
@@ -15872,6 +15802,8 @@
             background.setVisible(getVisibility() == VISIBLE, false);
             mBackground = background;
 
+            applyBackgroundTint();
+
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
                 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
                 mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
@@ -15927,6 +15859,88 @@
     }
 
     /**
+     * Applies a tint to the background drawable.
+     * <p>
+     * Subsequent calls to {@link #setBackground(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#View_backgroundTint
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     */
+    private void setBackgroundTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mBackgroundTint = tint;
+        mBackgroundTintMode = tintMode;
+        mHasBackgroundTint = true;
+
+        applyBackgroundTint();
+    }
+
+    /**
+     * Applies a tint to the background drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setBackground(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#View_backgroundTint
+     * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setBackgroundTint(@Nullable ColorStateList tint) {
+        setBackgroundTint(tint, mBackgroundTintMode);
+    }
+
+    /**
+     * @return the tint applied to the background drawable
+     * @attr ref android.R.styleable#View_backgroundTint
+     * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getBackgroundTint() {
+        return mBackgroundTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setBackgroundTint(ColorStateList)}} to the background drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see #setBackgroundTint(ColorStateList)
+     */
+    public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setBackgroundTint(mBackgroundTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the background drawable
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getBackgroundTintMode() {
+        return mBackgroundTintMode;
+    }
+
+    private void applyBackgroundTint() {
+        if (mBackground != null && mHasBackgroundTint) {
+            mBackground = mBackground.mutate();
+            mBackground.setTint(mBackgroundTint, mBackgroundTintMode);
+        }
+    }
+
+    /**
      * Sets the padding. The view may add on the space required to display
      * the scrollbars, depending on the style and visibility of the scrollbars.
      * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
@@ -19851,6 +19865,11 @@
          */
         final int[] mInvalidateChildLocation = new int[2];
 
+        /**
+         * Global to the view hierarchy used as a temporary for dealng with
+         * computing absolute on-screen location.
+         */
+        final int[] mTmpLocation = new int[2];
 
         /**
          * Global to the view hierarchy used as a temporary for dealing with
diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java
index 3854f34..29e865f 100644
--- a/core/java/android/view/ViewAnimationUtils.java
+++ b/core/java/android/view/ViewAnimationUtils.java
@@ -23,7 +23,7 @@
  * Defines common utilities for working with View's animations.
  *
  */
-public class ViewAnimationUtils {
+public final class ViewAnimationUtils {
     private ViewAnimationUtils() {}
     /**
      * Returns a ValueAnimator which can animate a clipping circle.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2905851..a02e76b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4386,10 +4386,9 @@
             // Make sure we do not set both flags at the same time
             int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
 
-            if (child.mLayerType != LAYER_TYPE_NONE) {
+            if (child.mLayerType == LAYER_TYPE_SOFTWARE) {
                 mPrivateFlags |= PFLAG_INVALIDATED;
                 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
-                child.mLocalDirtyRect.union(dirty);
             }
 
             final int[] location = attachInfo.mInvalidateChildLocation;
@@ -4498,9 +4497,8 @@
                 location[CHILD_LEFT_INDEX] = left;
                 location[CHILD_TOP_INDEX] = top;
 
-                if (mLayerType != LAYER_TYPE_NONE) {
+                if (mLayerType == LAYER_TYPE_SOFTWARE) {
                     mPrivateFlags |= PFLAG_INVALIDATED;
-                    mLocalDirtyRect.union(dirty);
                 }
 
                 return mParent;
@@ -4517,9 +4515,8 @@
                     dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
                 }
 
-                if (mLayerType != LAYER_TYPE_NONE) {
+                if (mLayerType == LAYER_TYPE_SOFTWARE) {
                     mPrivateFlags |= PFLAG_INVALIDATED;
-                    mLocalDirtyRect.union(dirty);
                 }
 
                 return mParent;
@@ -4567,10 +4564,6 @@
 
         final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            if (child.mLayerType != LAYER_TYPE_NONE) {
-                child.mLocalDirtyRect.union(dirty);
-            }
-
             int left = child.mLeft;
             int top = child.mTop;
             if (!child.getMatrix().isIdentity()) {
@@ -4618,9 +4611,6 @@
             if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
                     dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
 
-                if (mLayerType != LAYER_TYPE_NONE) {
-                    mLocalDirtyRect.union(dirty);
-                }
                 if (!getMatrix().isIdentity()) {
                     transformRect(dirty);
                 }
@@ -5600,11 +5590,11 @@
     @Override
     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
         insets = super.dispatchApplyWindowInsets(insets);
-        if (insets.hasInsets()) {
+        if (!insets.isConsumed()) {
             final int count = getChildCount();
             for (int i = 0; i < count; i++) {
                 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
-                if (!insets.hasInsets()) {
+                if (insets.isConsumed()) {
                     break;
                 }
             }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 76d5038..82e5ddd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,27 +631,7 @@
     }
 
     void destroyHardwareLayers() {
-        if (mThread != Thread.currentThread()) {
-            if (mAttachInfo.mHardwareRenderer != null &&
-                    mAttachInfo.mHardwareRenderer.isEnabled()) {
-                HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
-            }
-        } else {
-            destroyHardwareLayer(mView);
-        }
-    }
-
-    private static void destroyHardwareLayer(View view) {
-        view.destroyLayer(true);
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyHardwareLayer(group.getChildAt(i));
-            }
-        }
+        // TODO Implement
     }
 
     void flushHardwareLayerUpdates() {
@@ -676,7 +656,7 @@
     }
 
     public boolean invokeFunctor(long functor, boolean waitForCompletion) {
-        if (mAttachInfo.mHardwareRenderer == null || !mAttachInfo.mHardwareRenderer.isEnabled()) {
+        if (mAttachInfo.mHardwareRenderer == null) {
             return false;
         }
         mAttachInfo.mHardwareRenderer.invokeFunctor(functor, waitForCompletion);
@@ -720,7 +700,7 @@
                 }
 
                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
-                mAttachInfo.mHardwareRenderer = HardwareRenderer.create(translucent);
+                mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
                     mAttachInfo.mHardwareAccelerated =
@@ -1520,54 +1500,55 @@
 
                         disposeResizeBuffer();
 
-                        if (mResizeBuffer == null) {
-                            mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
-                                    mWidth, mHeight);
-                        }
-                        mResizeBuffer.prepare(mWidth, mHeight, false);
-                        RenderNode layerRenderNode = mResizeBuffer.startRecording();
-                        HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
-                        try {
-                            final int restoreCount = layerCanvas.save();
-
-                            int yoff;
-                            final boolean scrolling = mScroller != null
-                                    && mScroller.computeScrollOffset();
-                            if (scrolling) {
-                                yoff = mScroller.getCurrY();
-                                mScroller.abortAnimation();
-                            } else {
-                                yoff = mScrollY;
-                            }
-
-                            layerCanvas.translate(0, -yoff);
-                            if (mTranslator != null) {
-                                mTranslator.translateCanvas(layerCanvas);
-                            }
-
-                            RenderNode renderNode = mView.mRenderNode;
-                            if (renderNode != null && renderNode.isValid()) {
-                                layerCanvas.drawDisplayList(renderNode, null,
-                                        RenderNode.FLAG_CLIP_CHILDREN);
-                            } else {
-                                mView.draw(layerCanvas);
-                            }
-
-                            drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
-
-                            mResizeBufferStartTime = SystemClock.uptimeMillis();
-                            mResizeBufferDuration = mView.getResources().getInteger(
-                                    com.android.internal.R.integer.config_mediumAnimTime);
-
-                            layerCanvas.restoreToCount(restoreCount);
-                            layerRenderNode.end(layerCanvas);
-                            layerRenderNode.setCaching(true);
-                            layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
-                            mTempRect.set(0, 0, mWidth, mHeight);
-                        } finally {
-                            mResizeBuffer.endRecording(mTempRect);
-                        }
-                        mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+// TODO: Again....
+//                        if (mResizeBuffer == null) {
+//                            mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+//                                    mWidth, mHeight);
+//                        }
+//                        mResizeBuffer.prepare(mWidth, mHeight, false);
+//                        RenderNode layerRenderNode = mResizeBuffer.startRecording();
+//                        HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
+//                        try {
+//                            final int restoreCount = layerCanvas.save();
+//
+//                            int yoff;
+//                            final boolean scrolling = mScroller != null
+//                                    && mScroller.computeScrollOffset();
+//                            if (scrolling) {
+//                                yoff = mScroller.getCurrY();
+//                                mScroller.abortAnimation();
+//                            } else {
+//                                yoff = mScrollY;
+//                            }
+//
+//                            layerCanvas.translate(0, -yoff);
+//                            if (mTranslator != null) {
+//                                mTranslator.translateCanvas(layerCanvas);
+//                            }
+//
+//                            RenderNode renderNode = mView.mRenderNode;
+//                            if (renderNode != null && renderNode.isValid()) {
+//                                layerCanvas.drawDisplayList(renderNode, null,
+//                                        RenderNode.FLAG_CLIP_CHILDREN);
+//                            } else {
+//                                mView.draw(layerCanvas);
+//                            }
+//
+//                            drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+//
+//                            mResizeBufferStartTime = SystemClock.uptimeMillis();
+//                            mResizeBufferDuration = mView.getResources().getInteger(
+//                                    com.android.internal.R.integer.config_mediumAnimTime);
+//
+//                            layerCanvas.restoreToCount(restoreCount);
+//                            layerRenderNode.end(layerCanvas);
+//                            layerRenderNode.setCaching(true);
+//                            layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+//                            mTempRect.set(0, 0, mWidth, mHeight);
+//                        } finally {
+//                            mResizeBuffer.endRecording(mTempRect);
+//                        }
+//                        mAttachInfo.mHardwareRenderer.flushLayerUpdates();
                     }
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
@@ -6215,7 +6196,7 @@
             mTempRect.offset(0, -mCurScrollY);
             mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
             try {
-                mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
+                mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
             } catch (RemoteException re) {
                 /* ignore */
             }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index ecc4586..0120875 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1516,6 +1516,29 @@
     public boolean getAllowExitTransitionOverlap() { return true; }
 
     /**
+     * Returns the duration, in milliseconds, of the window background fade
+     * when transitioning into or away from an Activity when called with an Activity Transition.
+     * <p>When executing the enter transition, the background starts transparent
+     * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
+     * 300 milliseconds.</p>
+     * @return The duration of the window background fade to opaque during enter transition.
+     * @see #getEnterTransition()
+     */
+    public long getTransitionBackgroundFadeDuration() { return 0; }
+
+    /**
+     * Sets the duration, in milliseconds, of the window background fade
+     * when transitioning into or away from an Activity when called with an Activity Transition.
+     * <p>When executing the enter transition, the background starts transparent
+     * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
+     * 300 milliseconds.</p>
+     * @param fadeDurationMillis The duration of the window background fade to or from opaque
+     *                           during enter transition.
+     * @see #setEnterTransition(android.transition.Transition)
+     */
+    public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
+
+    /**
      * @return the color of the status bar.
      */
     public abstract int getStatusBarColor();
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 7f89044..b721074 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -111,6 +111,7 @@
         builder.append("type=").append(type);
         builder.append(", layer=").append(layer);
         builder.append(", token=").append(token);
+        builder.append(", bounds=").append(boundsInScreen);
         builder.append(", parent=").append(parentToken);
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 57e774e..1d2f1bf 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -35,6 +35,9 @@
     private Rect mTempRect;
     private boolean mIsRound;
 
+    private boolean mSystemWindowInsetsConsumed = false;
+    private boolean mWindowDecorInsetsConsumed = false;
+
     private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
 
     /**
@@ -43,7 +46,13 @@
      * since it would allow them to inadvertently consume unknown insets by returning it.
      * @hide
      */
-    public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+    public static final WindowInsets CONSUMED;
+
+    static {
+        CONSUMED = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+        CONSUMED.mSystemWindowInsetsConsumed = true;
+        CONSUMED.mWindowDecorInsetsConsumed = true;
+    }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
@@ -52,13 +61,17 @@
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets, boolean isRound) {
-        this(systemWindowInsets, EMPTY_RECT, isRound);
+        this(systemWindowInsets, null, isRound);
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
-        mSystemWindowInsets = systemWindowInsets;
-        mWindowDecorInsets = windowDecorInsets;
+        mSystemWindowInsetsConsumed = systemWindowInsets == null;
+        mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
+
+        mWindowDecorInsetsConsumed = windowDecorInsets == null;
+        mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;
+
         mIsRound = isRound;
     }
 
@@ -70,12 +83,14 @@
     public WindowInsets(WindowInsets src) {
         mSystemWindowInsets = src.mSystemWindowInsets;
         mWindowDecorInsets = src.mWindowDecorInsets;
+        mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
+        mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
         mIsRound = src.mIsRound;
     }
 
     /** @hide */
     public WindowInsets(Rect systemWindowInsets) {
-        this(systemWindowInsets, EMPTY_RECT);
+        this(systemWindowInsets, null);
     }
 
     /**
@@ -243,6 +258,24 @@
     }
 
     /**
+     * Check if these insets have been fully consumed.
+     *
+     * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
+     * have been called such that all insets have been set to zero. This affects propagation of
+     * insets through the view hierarchy; insets that have not been fully consumed will continue
+     * to propagate down to child views.</p>
+     *
+     * <p>The result of this method is equivalent to the return value of
+     * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
+     *
+     * @return true if the insets have been fully consumed.
+     * @hide Pending API
+     */
+    public boolean isConsumed() {
+        return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed;
+    }
+
+    /**
      * Returns true if the associated window has a round shape.
      *
      * <p>A round window's left, top, right and bottom edges reach all the way to the
@@ -263,7 +296,8 @@
      */
     public WindowInsets consumeSystemWindowInsets() {
         final WindowInsets result = new WindowInsets(this);
-        result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+        result.mSystemWindowInsets = EMPTY_RECT;
+        result.mSystemWindowInsetsConsumed = true;
         return result;
     }
 
@@ -281,10 +315,12 @@
             boolean right, boolean bottom) {
         if (left || top || right || bottom) {
             final WindowInsets result = new WindowInsets(this);
-            result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+            result.mSystemWindowInsets = new Rect(
+                    left ? 0 : mSystemWindowInsets.left,
                     top ? 0 : mSystemWindowInsets.top,
                     right ? 0 : mSystemWindowInsets.right,
                     bottom ? 0 : mSystemWindowInsets.bottom);
+            result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
             return result;
         }
         return this;
@@ -304,6 +340,7 @@
             int right, int bottom) {
         final WindowInsets result = new WindowInsets(this);
         result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+        result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
         return result;
     }
 
@@ -313,6 +350,7 @@
     public WindowInsets consumeWindowDecorInsets() {
         final WindowInsets result = new WindowInsets(this);
         result.mWindowDecorInsets.set(0, 0, 0, 0);
+        result.mWindowDecorInsetsConsumed = true;
         return result;
     }
 
@@ -327,6 +365,7 @@
                     top ? 0 : mWindowDecorInsets.top,
                     right ? 0 : mWindowDecorInsets.right,
                     bottom ? 0 : mWindowDecorInsets.bottom);
+            result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
             return result;
         }
         return this;
@@ -338,6 +377,7 @@
     public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
         final WindowInsets result = new WindowInsets(this);
         result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+        result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
         return result;
     }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 2b4677c..d426edc 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -605,21 +605,21 @@
     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation);
 
     /**
-     * Return whether the given window should forcibly hide everything
-     * behind it.  Typically returns true for the keyguard.
+     * Return whether the given window is forcibly hiding all windows except windows with
+     * FLAG_SHOW_WHEN_LOCKED set.  Typically returns true for the keyguard.
      */
-    public boolean doesForceHide(WindowManager.LayoutParams attrs);
+    public boolean isForceHiding(WindowManager.LayoutParams attrs);
 
 
     /**
-     * Return whether the given window can become one that passes doesForceHide() test.
+     * Return whether the given window can become one that passes isForceHiding() test.
      * Typically returns true for the StatusBar.
      */
     public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs);
 
     /**
      * Determine if a window that is behind one that is force hiding
-     * (as determined by {@link #doesForceHide}) should actually be hidden.
+     * (as determined by {@link #isForceHiding}) should actually be hidden.
      * For example, typically returns false for the status bar.  Be careful
      * to return false for any window that you may hide yourself, since this
      * will conflict with what you set.
@@ -830,13 +830,11 @@
      * setting the window's frame, either here or in finishLayout().
      * 
      * @param win The window being positioned.
-     * @param attrs The LayoutParams of the window.
      * @param attached For sub-windows, the window it is attached to; this
      *                 window will already have had layoutWindow() called on it
      *                 so you can use its Rect.  Otherwise null.
      */
-    public void layoutWindowLw(WindowState win,
-            WindowManager.LayoutParams attrs, WindowState attached);
+    public void layoutWindowLw(WindowState win, WindowState attached);
 
     
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 5b9372d..4748402 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -225,17 +225,11 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows();
-                if (windows != null) {
-                    if (DEBUG) {
-                        Log.i(LOG_TAG, "Window cache hit");
-                    }
-                    return windows;
-                }
-                if (DEBUG) {
-                    Log.i(LOG_TAG, "Window cache miss");
-                }
-                windows = connection.getWindows();
+                // The system is just sending data for windows that we introspected
+                // and changed but not ones that appeared, so we have to always call
+                // into the system process. This is less expensice as opposed to
+                // sending all windows on every window change.
+                List<AccessibilityWindowInfo> windows = connection.getWindows();
                 if (windows != null) {
                     final int windowCount = windows.size();
                     for (int i = 0; i < windowCount; i++) {
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index c08f348..1c75f16 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -17,15 +17,18 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
 import com.android.internal.view.animation.HasNativeInterpolator;
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
 
 /**
- * An interpolator where the rate of change starts out slowly and 
+ * An interpolator where the rate of change starts out slowly and
  * and then accelerates.
  *
  */
@@ -38,10 +41,10 @@
         mFactor = 1.0f;
         mDoubleFactor = 2.0;
     }
-    
+
     /**
      * Constructor
-     * 
+     *
      * @param factor Degree to which the animation should be eased. Seting
      *        factor to 1.0f produces a y=x^2 parabola. Increasing factor above
      *        1.0f  exaggerates the ease-in effect (i.e., it starts even
@@ -51,17 +54,26 @@
         mFactor = factor;
         mDoubleFactor = 2 * mFactor;
     }
-    
+
     public AccelerateInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a =
-            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
-        
-        mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
+        }
+
+        mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
         mDoubleFactor = 2 * mFactor;
 
         a.recycle();
     }
-    
+
     public float getInterpolation(float input) {
         if (mFactor == 1.0f) {
             return input * input;
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 1d1fa1e..af4e04f 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -20,6 +20,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
 import android.content.res.Resources.NotFoundException;
 import android.util.AttributeSet;
@@ -143,7 +145,7 @@
      */
     public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
             throws NotFoundException {
-        
+
         XmlResourceParser parser = null;
         try {
             parser = context.getResources().getAnimation(id);
@@ -201,7 +203,7 @@
     /**
      * Make an animation for objects becoming visible. Uses a slide and fade
      * effect.
-     * 
+     *
      * @param c Context for loading resources
      * @param fromLeft is the object to be animated coming from the left
      * @return The new animation
@@ -218,11 +220,11 @@
         a.setStartTime(currentAnimationTimeMillis());
         return a;
     }
-    
+
     /**
      * Make an animation for objects becoming invisible. Uses a slide and fade
      * effect.
-     * 
+     *
      * @param c Context for loading resources
      * @param toRight is the object to be animated exiting to the right
      * @return The new animation
@@ -234,17 +236,17 @@
         } else {
             a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left);
         }
-        
+
         a.setInterpolator(new AccelerateInterpolator());
         a.setStartTime(currentAnimationTimeMillis());
         return a;
     }
 
-    
+
     /**
      * Make an animation for objects becoming visible. Uses a slide up and fade
      * effect.
-     * 
+     *
      * @param c Context for loading resources
      * @return The new animation
      */
@@ -255,10 +257,10 @@
         a.setStartTime(currentAnimationTimeMillis());
         return a;
     }
-    
+
     /**
      * Loads an {@link Interpolator} object from a resource
-     * 
+     *
      * @param context Application context used to access resources
      * @param id The resource id of the animation to load
      * @return The animation object reference by the specified id
@@ -268,7 +270,7 @@
         XmlResourceParser parser = null;
         try {
             parser = context.getResources().getAnimation(id);
-            return createInterpolatorFromXml(context, parser);
+            return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser);
         } catch (XmlPullParserException ex) {
             NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
                     Integer.toHexString(id));
@@ -284,54 +286,84 @@
         }
 
     }
-    
-    private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser)
+
+    /**
+     * Loads an {@link Interpolator} object from a resource
+     *
+     * @param res The resources
+     * @param id The resource id of the animation to load
+     * @return The interpolator object reference by the specified id
+     * @throws NotFoundException
+     * @hide
+     */
+    public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException {
+        XmlResourceParser parser = null;
+        try {
+            parser = res.getAnimation(id);
+            return createInterpolatorFromXml(res, theme, parser);
+        } catch (XmlPullParserException ex) {
+            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
+                    Integer.toHexString(id));
+            rnf.initCause(ex);
+            throw rnf;
+        } catch (IOException ex) {
+            NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
+                    Integer.toHexString(id));
+            rnf.initCause(ex);
+            throw rnf;
+        } finally {
+            if (parser != null)
+                parser.close();
+        }
+
+    }
+
+    private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
             throws XmlPullParserException, IOException {
-        
+
         Interpolator interpolator = null;
- 
+
         // Make sure we are on a start tag.
         int type;
         int depth = parser.getDepth();
 
-        while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
-               && type != XmlPullParser.END_DOCUMENT) {
+        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+                && type != XmlPullParser.END_DOCUMENT) {
 
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
 
             AttributeSet attrs = Xml.asAttributeSet(parser);
-            
-            String  name = parser.getName();
-    
-            
+
+            String name = parser.getName();
+
             if (name.equals("linearInterpolator")) {
-                interpolator = new LinearInterpolator(c, attrs);
+                interpolator = new LinearInterpolator();
             } else if (name.equals("accelerateInterpolator")) {
-                interpolator = new AccelerateInterpolator(c, attrs);
+                interpolator = new AccelerateInterpolator(res, theme, attrs);
             } else if (name.equals("decelerateInterpolator")) {
-                interpolator = new DecelerateInterpolator(c, attrs);
-            }  else if (name.equals("accelerateDecelerateInterpolator")) {
-                interpolator = new AccelerateDecelerateInterpolator(c, attrs);
-            }  else if (name.equals("cycleInterpolator")) {
-                interpolator = new CycleInterpolator(c, attrs);
+                interpolator = new DecelerateInterpolator(res, theme, attrs);
+            } else if (name.equals("accelerateDecelerateInterpolator")) {
+                interpolator = new AccelerateDecelerateInterpolator();
+            } else if (name.equals("cycleInterpolator")) {
+                interpolator = new CycleInterpolator(res, theme, attrs);
             } else if (name.equals("anticipateInterpolator")) {
-                interpolator = new AnticipateInterpolator(c, attrs);
+                interpolator = new AnticipateInterpolator(res, theme, attrs);
             } else if (name.equals("overshootInterpolator")) {
-                interpolator = new OvershootInterpolator(c, attrs);
+                interpolator = new OvershootInterpolator(res, theme, attrs);
             } else if (name.equals("anticipateOvershootInterpolator")) {
-                interpolator = new AnticipateOvershootInterpolator(c, attrs);
+                interpolator = new AnticipateOvershootInterpolator(res, theme, attrs);
             } else if (name.equals("bounceInterpolator")) {
-                interpolator = new BounceInterpolator(c, attrs);
+                interpolator = new BounceInterpolator();
             } else if (name.equals("pathInterpolator")) {
-                interpolator = new PathInterpolator(c, attrs);
+                interpolator = new PathInterpolator(res, theme, attrs);
             } else {
                 throw new RuntimeException("Unknown interpolator name: " + parser.getName());
             }
 
         }
-    
+
         return interpolator;
 
     }
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index 83a8007..fe756bd 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -17,9 +17,12 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
 import com.android.internal.view.animation.HasNativeInterpolator;
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -45,11 +48,20 @@
     }
 
     public AnticipateInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                com.android.internal.R.styleable.AnticipateInterpolator);
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public AnticipateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.AnticipateInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
+        }
 
         mTension =
-                a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);
+                a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
 
         a.recycle();
     }
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 1a8adfd..78e5acf 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -17,6 +17,8 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
@@ -62,7 +64,17 @@
     }
 
     public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public AnticipateOvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, AnticipateOvershootInterpolator);
+        }
 
         mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
                 a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index d1ebf05..3114aa3 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -17,9 +17,12 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
 import com.android.internal.view.animation.HasNativeInterpolator;
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -34,20 +37,29 @@
     public CycleInterpolator(float cycles) {
         mCycles = cycles;
     }
-    
+
     public CycleInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a =
-            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator);
-        
-        mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f);
-        
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public CycleInterpolator(Resources resources, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.CycleInterpolator, 0, 0);
+        } else {
+            a = resources.obtainAttributes(attrs, R.styleable.CycleInterpolator);
+        }
+
+        mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
+
         a.recycle();
     }
-    
+
     public float getInterpolation(float input) {
         return (float)(Math.sin(2 * mCycles * Math.PI * input));
     }
-    
+
     private float mCycles;
 
     /** @hide */
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 0789a0e..674207c 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -17,15 +17,18 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
 import com.android.internal.view.animation.HasNativeInterpolator;
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
 
 /**
- * An interpolator where the rate of change starts out quickly and 
+ * An interpolator where the rate of change starts out quickly and
  * and then decelerates.
  *
  */
@@ -36,7 +39,7 @@
 
     /**
      * Constructor
-     * 
+     *
      * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
      *        an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
      *        ease-out effect (i.e., it starts even faster and ends evens slower)
@@ -44,16 +47,25 @@
     public DecelerateInterpolator(float factor) {
         mFactor = factor;
     }
-    
+
     public DecelerateInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a =
-            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator);
-        
-        mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f);
-        
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public DecelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.DecelerateInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.DecelerateInterpolator);
+        }
+
+        mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);
+
         a.recycle();
     }
-    
+
     public float getInterpolation(float input) {
         float result;
         if (mFactor == 1.0f) {
@@ -63,7 +75,7 @@
         }
         return result;
     }
-    
+
     private float mFactor = 1.0f;
 
     /** @hide */
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index a2466f1..d6c2808 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -17,9 +17,12 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
 import com.android.internal.view.animation.HasNativeInterpolator;
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -46,11 +49,20 @@
     }
 
     public OvershootInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                com.android.internal.R.styleable.OvershootInterpolator);
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public OvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.OvershootInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator);
+        }
 
         mTension =
-                a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f);
+                a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
 
         a.recycle();
     }
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index a369509..da12ffb 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -16,11 +16,15 @@
 package android.view.animation;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Path;
 import android.util.AttributeSet;
 import android.view.InflateException;
 
+import com.android.internal.R;
+
 /**
  * An interpolator that can traverse a Path that extends from <code>Point</code>
  * <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code>
@@ -81,18 +85,33 @@
     }
 
     public PathInterpolator(Context context, AttributeSet attrs) {
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                com.android.internal.R.styleable.PathInterpolator);
-        if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX1)) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
+        }
+        parseInterpolatorFromTypeArray(a);
+
+        a.recycle();
+    }
+
+    private void parseInterpolatorFromTypeArray(TypedArray a) {
+        if (!a.hasValue(R.styleable.PathInterpolator_controlX1)) {
             throw new InflateException("pathInterpolator requires the controlX1 attribute");
-        } else if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY1)) {
+        } else if (!a.hasValue(R.styleable.PathInterpolator_controlY1)) {
             throw new InflateException("pathInterpolator requires the controlY1 attribute");
         }
-        float x1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX1, 0);
-        float y1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY1, 0);
+        float x1 = a.getFloat(R.styleable.PathInterpolator_controlX1, 0);
+        float y1 = a.getFloat(R.styleable.PathInterpolator_controlY1, 0);
 
-        boolean hasX2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX2);
-        boolean hasY2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY2);
+        boolean hasX2 = a.hasValue(R.styleable.PathInterpolator_controlX2);
+        boolean hasY2 = a.hasValue(R.styleable.PathInterpolator_controlY2);
 
         if (hasX2 != hasY2) {
             throw new InflateException(
@@ -102,12 +121,10 @@
         if (!hasX2) {
             initQuad(x1, y1);
         } else {
-            float x2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX2, 0);
-            float y2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY2, 0);
+            float x2 = a.getFloat(R.styleable.PathInterpolator_controlX2, 0);
+            float y2 = a.getFloat(R.styleable.PathInterpolator_controlY2, 0);
             initCubic(x1, y1, x2, y2);
         }
-
-        a.recycle();
     }
 
     private void initQuad(float controlX, float controlY) {
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index fad6747..66f5f6c 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -186,12 +186,12 @@
     /**
      * Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
      */
-    public static final class CursorAnchorInfoBuilder {
+    public static final class Builder {
         /**
          * 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) {
+        public Builder setSelectionRange(final int newStart, final int newEnd) {
             mSelectionStart = newStart;
             mSelectionEnd = newEnd;
             return this;
@@ -205,8 +205,7 @@
          * @param index index where the composing text starts.
          * @param composingText the entire composing text.
          */
-        public CursorAnchorInfoBuilder setComposingText(final int index,
-                final CharSequence composingText) {
+        public Builder setComposingText(final int index, final CharSequence composingText) {
             mComposingTextStart = index;
             if (composingText == null) {
                 mComposingText = null;
@@ -236,9 +235,8 @@
          * 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){
+        public Builder setInsertionMarkerLocation(final float horizontalPosition,
+                final float lineTop, final float lineBaseline, final float lineBottom){
             mInsertionMarkerHorizontal = horizontalPosition;
             mInsertionMarkerTop = lineTop;
             mInsertionMarkerBaseline = lineBaseline;
@@ -269,9 +267,8 @@
          * @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) {
+        public Builder 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.");
             }
@@ -289,7 +286,7 @@
          * @param matrix transformation matrix from local coordinates into screen coordinates. null
          * is interpreted as an identity matrix.
          */
-        public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) {
+        public Builder setMatrix(final Matrix matrix) {
             mMatrix.set(matrix != null ? matrix : Matrix.IDENTITY_MATRIX);
             return this;
         }
@@ -297,7 +294,7 @@
 
         /**
          * @return {@link CursorAnchorInfo} using parameters in this
-         * {@link CursorAnchorInfoBuilder}.
+         * {@link Builder}.
          */
         public CursorAnchorInfo build() {
             return new CursorAnchorInfo(this);
@@ -323,7 +320,7 @@
         }
     }
 
-    private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) {
+    private CursorAnchorInfo(final Builder builder) {
         mSelectionStart = builder.mSelectionStart;
         mSelectionEnd = builder.mSelectionEnd;
         mComposingTextStart = builder.mComposingTextStart;
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
index 588b868..4a7f5fd 100644
--- a/core/java/android/webkit/ClientCertRequest.java
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -27,7 +27,7 @@
  * such as the host name and the port number requesting the cert, the acceptable
  * key types and the principals.
  *
- * The user should call one of the interface methods to indicate how to deal
+ * The user should call one of the class methods to indicate how to deal
  * with the client certificate request. All methods should be called on
  * UI thread.
  *
@@ -37,42 +37,45 @@
  * {@link WebView#clearClientCertPreferences}.
  *
  */
-public interface ClientCertRequest {
+public abstract class ClientCertRequest {
+
+    public ClientCertRequest() { }
+
     /**
      * Returns the acceptable types of asymmetric keys (can be null).
      */
-    public String[] getKeyTypes();
+    public abstract String[] getKeyTypes();
 
     /**
      * Returns the acceptable certificate issuers for the certificate
      *            matching the private key (can be null).
      */
-    public Principal[] getPrincipals();
+    public abstract Principal[] getPrincipals();
 
     /**
      * Returns the host name of the server requesting the certificate.
      */
-    public String getHost();
+    public abstract String getHost();
 
     /**
      * Returns the port number of the server requesting the certificate.
      */
-    public int getPort();
+    public abstract int getPort();
 
     /**
      * Proceed with the specified private key and client certificate chain.
      * Remember the user's positive choice and use it for future requests.
      */
-    public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+    public abstract void proceed(PrivateKey privateKey, X509Certificate[] chain);
 
     /**
      * Ignore the request for now. Do not remember user's choice.
      */
-    public void ignore();
+    public abstract void ignore();
 
     /**
      * Cancel this request. Remember the user's choice and use it for
      * future requests.
      */
-    public void cancel();
+    public abstract void cancel();
 }
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index abed082..321d9d3 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -17,6 +17,7 @@
 package android.webkit;
 
 import android.net.WebAddress;
+import android.webkit.ValueCallback;
 
 /**
  * Manages the cookies used by an application's {@link WebView} instances.
@@ -72,7 +73,7 @@
      * path and name will be replaced with the new cookie. The cookie being set
      * will be ignored if it is expired.
      *
-     * @param url the URL for which the cookie is set
+     * @param url the URL for which the cookie is to be set
      * @param value the cookie as a string, using the format of the 'Set-Cookie'
      *              HTTP response header
      */
@@ -81,6 +82,29 @@
     }
 
     /**
+     * Sets a cookie for the given URL. Any existing cookie with the same host,
+     * path and name will be replaced with the new cookie. The cookie being set
+     * will be ignored if it is expired.
+     * <p>
+     * This method is asynchronous.
+     * If a {@link ValueCallback} is provided,
+     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+     * thread's {@link android.os.Looper} once the operation is complete.
+     * The value provided to the callback indicates whether the cookie was set successfully.
+     * You can pass {@code null} as the callback if you don't need to know when the operation
+     * completes or whether it succeeded, and in this case it is safe to call the method from a
+     * thread without a Looper.
+     *
+     * @param url the URL for which the cookie is to be set
+     * @param value the cookie as a string, using the format of the 'Set-Cookie'
+     *              HTTP response header
+     * @param callback a callback to be executed when the cookie has been set
+     */
+    public void setCookie(String url, String value, ValueCallback<Boolean> callback) {
+        throw new MustOverrideException();
+    }
+
+    /**
      * Gets the cookies for the given URL.
      *
      * @param url the URL for which the cookies are requested
@@ -120,19 +144,57 @@
     /**
      * Removes all session cookies, which are cookies without an expiration
      * date.
+     * @deprecated use {@link #removeSessionCookies(ValueCallback)} instead.
      */
     public void removeSessionCookie() {
         throw new MustOverrideException();
     }
 
     /**
-     * Removes all cookies.
+     * Removes all session cookies, which are cookies without an expiration
+     * date.
+     * <p>
+     * This method is asynchronous.
+     * If a {@link ValueCallback} is provided,
+     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+     * thread's {@link android.os.Looper} once the operation is complete.
+     * The value provided to the callback indicates whether any cookies were removed.
+     * You can pass {@code null} as the callback if you don't need to know when the operation
+     * completes or whether any cookie were removed, and in this case it is safe to call the
+     * method from a thread without a Looper.
+     * @param callback a callback which is executed when the session cookies have been removed
      */
+    public void removeSessionCookies(ValueCallback<Boolean> callback) {
+        throw new MustOverrideException();
+    }
+
+    /**
+     * Removes all cookies.
+     * @deprecated Use {@link #removeAllCookies(ValueCallback)} instead.
+     */
+    @Deprecated
     public void removeAllCookie() {
         throw new MustOverrideException();
     }
 
     /**
+     * Removes all cookies.
+     * <p>
+     * This method is asynchronous.
+     * If a {@link ValueCallback} is provided,
+     * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+     * thread's {@link android.os.Looper} once the operation is complete.
+     * The value provided to the callback indicates whether any cookies were removed.
+     * You can pass {@code null} as the callback if you don't need to know when the operation
+     * completes or whether any cookies were removed, and in this case it is safe to call the
+     * method from a thread without a Looper.
+     * @param callback a callback which is executed when the cookies have been removed
+     */
+    public void removeAllCookies(ValueCallback<Boolean> callback) {
+        throw new MustOverrideException();
+    }
+
+    /**
      * Gets whether there are stored cookies.
      *
      * @return true if there are stored cookies
@@ -153,7 +215,9 @@
 
     /**
      * Removes all expired cookies.
+     * @deprecated The WebView handles removing expired cookies automatically.
      */
+    @Deprecated
     public void removeExpiredCookie() {
         throw new MustOverrideException();
     }
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index ec396aa..470d413 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -408,7 +408,6 @@
      * @return true if filePathCallback will be invoked, false to use default handling.
      *
      * @see FileChooserParams
-     * @hide For API approval
      */
     public boolean showFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
             FileChooserParams fileChooserParams) {
@@ -416,11 +415,8 @@
     }
 
     /**
-     * Parameters used in the {@link #showFileChooser(WebView,ValueCallback<String[]>,FileChooserParams)}
-     * method.
-     *
+     * Parameters used in the {@link #showFileChooser} method.
      * This is intended to be used as a read-only data struct by the application.
-     * @hide For API approval
      */
     public static class FileChooserParams {
         // Flags for mode
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 91ca7b4..482c7e8 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1486,11 +1486,11 @@
     }
 
     /**
-     * Clears the client certificate preferences table stored in response
-     * to proceeding/cancelling client cert requests. Note that webview
+     * Clears the client certificate preferences stored in response
+     * to proceeding/cancelling client cert requests. Note that Webview
      * automatically clears these preferences when it receives a
-     * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The client certificate
-     * preferences are global for all Webviews.
+     * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are
+     * shared by all the webviews that are created by the embedder application.
      *
      * @param onCleared  A runnable to be invoked when client certs are cleared.
      *                   The embedder can pass null if not interested in the
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 43f623b..eb3f882 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -16,11 +16,15 @@
 
 package android.widget;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Insets;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -31,10 +35,16 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.internal.R;
+
 public abstract class AbsSeekBar extends ProgressBar {
     private final Rect mTempRect = new Rect();
 
     private Drawable mThumb;
+    private ColorStateList mThumbTint = null;
+    private PorterDuff.Mode mThumbTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasThumbTint = false;
+
     private int mThumbOffset;
     private boolean mSplitTrack;
 
@@ -83,6 +93,15 @@
         final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
         setThumb(thumb);
 
+        if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
+            mThumbTint = a.getColorStateList(R.styleable.SeekBar_thumbTint);
+            mThumbTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
+            mHasThumbTint = true;
+
+            applyThumbTint();
+        }
+
         // Guess thumb offset if thumb != null, but allow layout to override.
         final int thumbOffset = a.getDimensionPixelOffset(
                 com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
@@ -108,7 +127,7 @@
      * @param thumb Drawable representing the thumb
      */
     public void setThumb(Drawable thumb) {
-        boolean needUpdate;
+        final boolean needUpdate;
         // This way, calling setThumb again with the same bitmap will result in
         // it recalcuating mThumbOffset (if for example it the bounds of the
         // drawable changed)
@@ -118,6 +137,7 @@
         } else {
             needUpdate = false;
         }
+
         if (thumb != null) {
             thumb.setCallback(this);
             if (canResolveLayoutDirection()) {
@@ -136,8 +156,12 @@
                 requestLayout();
             }
         }
+
         mThumb = thumb;
+
+        applyThumbTint();
         invalidate();
+
         if (needUpdate) {
             updateThumbAndTrackPos(getWidth(), getHeight());
             if (thumb != null && thumb.isStateful()) {
@@ -160,6 +184,88 @@
     }
 
     /**
+     * Applies a tint to the thumb drawable.
+     * <p>
+     * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#SeekBar_thumbTint
+     * @attr ref android.R.styleable#SeekBar_thumbTintMode
+     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     */
+    private void setThumbTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mThumbTint = tint;
+        mThumbTintMode = tintMode;
+        mHasThumbTint = true;
+
+        applyThumbTint();
+    }
+
+    /**
+     * Applies a tint to the thumb drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#SeekBar_thumbTint
+     * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setThumbTint(@Nullable ColorStateList tint) {
+        setThumbTint(tint, mThumbTintMode);
+    }
+
+    /**
+     * @return the tint applied to the thumb drawable
+     * @attr ref android.R.styleable#SeekBar_thumbTint
+     * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getThumbTint() {
+        return mThumbTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setThumbTint(ColorStateList)}} to the thumb drawable. The
+     * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#SeekBar_thumbTintMode
+     * @see #setThumbTint(ColorStateList)
+     */
+    public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setThumbTint(mThumbTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the thumb drawable
+     * @attr ref android.R.styleable#SeekBar_thumbTintMode
+     * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getThumbTintMode() {
+        return mThumbTintMode;
+    }
+
+    private void applyThumbTint() {
+        if (mThumb != null && mHasThumbTint) {
+            mThumb = mThumb.mutate();
+            mThumb.setTint(mThumbTint, mThumbTintMode);
+        }
+    }
+
+    /**
      * @see #setThumbOffset(int)
      */
     public int getThumbOffset() {
@@ -255,6 +361,22 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        final Drawable progressDrawable = getProgressDrawable();
+        if (progressDrawable != null) {
+            progressDrawable.setHotspot(x, y);
+        }
+
+        final Drawable thumb = mThumb;
+        if (thumb != null) {
+            thumb.setHotspot(x, y);
+        }
+    }
+
     @Override
     public void invalidateDrawable(Drawable dr) {
         super.invalidateDrawable(dr);
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 3ae9508..7113793 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -307,6 +307,16 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mCheckMarkDrawable != null) {
+            mCheckMarkDrawable.setHotspot(x, y);
+        }
+    }
+
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 6aff4f4..747d2b1 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -16,11 +16,15 @@
 
 package android.widget;
 
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
 import com.android.internal.R;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -48,7 +52,12 @@
     private boolean mChecked;
     private int mButtonResource;
     private boolean mBroadcasting;
+
     private Drawable mButtonDrawable;
+    private ColorStateList mButtonTint = null;
+    private PorterDuff.Mode mButtonTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasButtonTint = false;
+
     private OnCheckedChangeListener mOnCheckedChangeListener;
     private OnCheckedChangeListener mOnCheckedChangeWidgetListener;
 
@@ -74,13 +83,22 @@
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);
 
-        Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
+        final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
         if (d != null) {
             setButtonDrawable(d);
         }
 
-        boolean checked = a
-                .getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
+        if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
+            mButtonTint = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
+            mButtonTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.CompoundButton_buttonTintMode, -1), mButtonTintMode);
+            mHasButtonTint = true;
+
+            applyButtonTint();
+        }
+
+        final boolean checked = a.getBoolean(
+                com.android.internal.R.styleable.CompoundButton_checked, false);
         setChecked(checked);
 
         a.recycle();
@@ -173,9 +191,11 @@
     }
 
     /**
-     * Set the background to a given Drawable, identified by its resource id.
+     * Set the button graphic to a given Drawable, identified by its resource
+     * id.
      *
-     * @param resid the resource id of the drawable to use as the background 
+     * @param resid the resource id of the drawable to use as the button
+     *        graphic
      */
     public void setButtonDrawable(int resid) {
         if (resid != 0 && resid == mButtonResource) {
@@ -192,23 +212,114 @@
     }
 
     /**
-     * Set the background to a given Drawable
+     * Set the button graphic to a given Drawable
      *
-     * @param d The Drawable to use as the background
+     * @param d The Drawable to use as the button graphic
      */
     public void setButtonDrawable(Drawable d) {
-        if (d != null) {
+        if (mButtonDrawable != d) {
             if (mButtonDrawable != null) {
                 mButtonDrawable.setCallback(null);
                 unscheduleDrawable(mButtonDrawable);
             }
-            d.setCallback(this);
-            d.setVisible(getVisibility() == VISIBLE, false);
-            mButtonDrawable = d;
-            setMinHeight(mButtonDrawable.getIntrinsicHeight());
-        }
 
-        refreshDrawableState();
+            mButtonDrawable = d;
+
+            if (d != null) {
+                d.setCallback(this);
+                d.setLayoutDirection(getLayoutDirection());
+                if (d.isStateful()) {
+                    d.setState(getDrawableState());
+                }
+                d.setVisible(getVisibility() == VISIBLE, false);
+                setMinHeight(d.getIntrinsicHeight());
+                applyButtonTint();
+            }
+        }
+    }
+
+    /**
+     * Applies a tint to the button drawable.
+     * <p>
+     * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#CompoundButton_buttonTint
+     * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+     * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+     */
+    private void setButtonTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mButtonTint = tint;
+        mButtonTintMode = tintMode;
+        mHasButtonTint = true;
+
+        applyButtonTint();
+    }
+
+    /**
+     * Applies a tint to the button drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#CompoundButton_buttonTint
+     * @see #setButtonTint(ColorStateList, android.graphics.PorterDuff.Mode)
+     */
+    public void setButtonTint(@Nullable ColorStateList tint) {
+        setButtonTint(tint, mButtonTintMode);
+    }
+
+    /**
+     * @return the tint applied to the button drawable
+     * @attr ref android.R.styleable#CompoundButton_buttonTint
+     * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getButtonTint() {
+        return mButtonTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setButtonTint(ColorStateList)}} to the button drawable. The
+     * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+     * @see #setButtonTint(ColorStateList)
+     */
+    public void setButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setButtonTint(mButtonTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the button drawable
+     * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+     * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getButtonTintMode() {
+        return mButtonTintMode;
+    }
+
+    private void applyButtonTint() {
+        if (mButtonDrawable != null && mHasButtonTint) {
+            mButtonDrawable = mButtonDrawable.mutate();
+            mButtonDrawable.setTint(mButtonTint, mButtonTintMode);
+        }
     }
 
     @Override
@@ -320,6 +431,16 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mButtonDrawable != null) {
+            mButtonDrawable.setHotspot(x, y);
+        }
+    }
+
     @Override
     protected boolean verifyDrawable(Drawable who) {
         return super.verifyDrawable(who) || who == mButtonDrawable;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 27d6b82..4467128 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -96,7 +96,6 @@
 import android.view.WindowManager;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -3013,7 +3012,7 @@
      * {@link InputMethodManager#isWatchingCursor(View)} returns false.
      */
     private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
-        final CursorAnchorInfoBuilder mSelectionInfoBuilder = new CursorAnchorInfoBuilder();
+        final CursorAnchorInfo.Builder mSelectionInfoBuilder = new CursorAnchorInfo.Builder();
         final int[] mTmpIntOffset = new int[2];
         final Matrix mViewToScreenMatrix = new Matrix();
 
@@ -3037,7 +3036,7 @@
                 return;
             }
 
-            final CursorAnchorInfoBuilder builder = mSelectionInfoBuilder;
+            final CursorAnchorInfo.Builder builder = mSelectionInfoBuilder;
             builder.reset();
 
             final int selectionStart = mTextView.getSelectionStart();
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index b029328..5a14929 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -18,11 +18,15 @@
 
 import java.util.ArrayList;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
@@ -33,6 +37,8 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 
 /**
  * FrameLayout is designed to block out an area on the screen to display
@@ -62,6 +68,9 @@
 
     @ViewDebug.ExportedProperty(category = "drawing")
     private Drawable mForeground;
+    private ColorStateList mForegroundTint = null;
+    private PorterDuff.Mode mForegroundTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasForegroundTint = false;
 
     @ViewDebug.ExportedProperty(category = "padding")
     private int mForegroundPaddingLeft = 0;
@@ -119,6 +128,15 @@
             setMeasureAllChildren(true);
         }
 
+        if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) {
+            mForegroundTint = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
+            mForegroundTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode);
+            mHasForegroundTint = true;
+
+            applyForegroundTint();
+        }
+
         mForegroundInPadding = a.getBoolean(
                 com.android.internal.R.styleable.FrameLayout_foregroundInsidePadding, true);
 
@@ -205,6 +223,16 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mForeground != null) {
+            mForeground.setHotspot(x, y);
+        }
+    }
+
     /**
      * Returns a set of layout parameters with a width of
      * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
@@ -221,32 +249,34 @@
      * into account by ensuring that the children are inset to be placed
      * inside of the padding area.
      * 
-     * @param drawable The Drawable to be drawn on top of the children.
+     * @param d The Drawable to be drawn on top of the children.
      * 
      * @attr ref android.R.styleable#FrameLayout_foreground
      */
-    public void setForeground(Drawable drawable) {
-        if (mForeground != drawable) {
+    public void setForeground(Drawable d) {
+        if (mForeground != d) {
             if (mForeground != null) {
                 mForeground.setCallback(null);
                 unscheduleDrawable(mForeground);
             }
 
-            mForeground = drawable;
+            mForeground = d;
             mForegroundPaddingLeft = 0;
             mForegroundPaddingTop = 0;
             mForegroundPaddingRight = 0;
             mForegroundPaddingBottom = 0;
 
-            if (drawable != null) {
+            if (d != null) {
                 setWillNotDraw(false);
-                drawable.setCallback(this);
-                if (drawable.isStateful()) {
-                    drawable.setState(getDrawableState());
+                d.setCallback(this);
+                d.setLayoutDirection(getLayoutDirection());
+                if (d.isStateful()) {
+                    d.setState(getDrawableState());
                 }
+                applyForegroundTint();
                 if (mForegroundGravity == Gravity.FILL) {
                     Rect padding = new Rect();
-                    if (drawable.getPadding(padding)) {
+                    if (d.getPadding(padding)) {
                         mForegroundPaddingLeft = padding.left;
                         mForegroundPaddingTop = padding.top;
                         mForegroundPaddingRight = padding.right;
@@ -271,6 +301,89 @@
         return mForeground;
     }
 
+    /**
+     * Applies a tint to the foreground drawable.
+     * <p>
+     * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#FrameLayout_foregroundTint
+     * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     */
+    private void setForegroundTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mForegroundTint = tint;
+        mForegroundTintMode = tintMode;
+        mHasForegroundTint = true;
+
+        applyForegroundTint();
+    }
+
+    /**
+     * Applies a tint to the foreground drawable. Does not modify the current
+     * tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#FrameLayout_foregroundTint
+     * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setForegroundTint(@Nullable ColorStateList tint) {
+        setForegroundTint(tint, mForegroundTintMode);
+    }
+
+    /**
+     * @return the tint applied to the foreground drawable
+     * @attr ref android.R.styleable#FrameLayout_foregroundTint
+     * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getForegroundTint() {
+        return mForegroundTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setForegroundTint(ColorStateList)}} to the foreground drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+     * @see #setForegroundTint(ColorStateList)
+     */
+    public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setForegroundTint(mForegroundTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the foreground
+     *         drawable
+     * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+     * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getForegroundTintMode() {
+        return mForegroundTintMode;
+    }
+
+    private void applyForegroundTint() {
+        if (mForeground != null && mHasForegroundTint) {
+            mForeground = mForeground.mutate();
+            mForeground.setTint(mForegroundTint, mForegroundTintMode);
+        }
+    }
+
     int getPaddingLeftWithForeground() {
         return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
             mPaddingLeft + mForegroundPaddingLeft;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 572302a4..399e087 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -16,8 +16,10 @@
 
 package android.widget;
 
+import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -30,6 +32,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Xfermode;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -44,6 +47,8 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -75,13 +80,18 @@
     private int mMaxHeight = Integer.MAX_VALUE;
 
     // these are applied to the drawable
-    private ColorFilter mColorFilter;
+    private ColorFilter mColorFilter = null;
+    private boolean mHasColorFilter = false;
     private Xfermode mXfermode;
     private int mAlpha = 255;
     private int mViewAlphaScale = 256;
     private boolean mColorMod = false;
 
     private Drawable mDrawable = null;
+    private ColorStateList mDrawableTint = null;
+    private PorterDuff.Mode mDrawableTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasDrawableTint = false;
+
     private int[] mState = null;
     private boolean mMergeState = false;
     private int mLevel = 0;
@@ -154,17 +164,21 @@
         setMaxHeight(a.getDimensionPixelSize(
                 com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
         
-        int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
+        final int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
         if (index >= 0) {
             setScaleType(sScaleTypeArray[index]);
         }
 
-        int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
-        if (tint != 0) {
-            setColorFilter(tint);
+        if (a.hasValue(R.styleable.ImageView_tint)) {
+            mDrawableTint = a.getColorStateList(R.styleable.ImageView_tint);
+            mDrawableTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.ImageView_tintMode, -1), mDrawableTintMode);
+            mHasDrawableTint = true;
+
+            applyDrawableTint();
         }
-        
-        int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+
+        final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
         if (alpha != 255) {
             setAlpha(alpha);
         }
@@ -435,6 +449,88 @@
     }
 
     /**
+     * Applies a tint to the image drawable.
+     * <p>
+     * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ImageView_tint
+     * @attr ref android.R.styleable#ImageView_tintMode
+     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     */
+    private void setTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mDrawableTint = tint;
+        mDrawableTintMode = tintMode;
+        mHasDrawableTint = true;
+
+        applyDrawableTint();
+    }
+
+    /**
+     * Applies a tint to the image drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ImageView_tint
+     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setTint(@Nullable ColorStateList tint) {
+        setTint(tint, mDrawableTintMode);
+    }
+
+    /**
+     * @return the tint applied to the image drawable
+     * @attr ref android.R.styleable#ImageView_tint
+     * @see #setTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getTint() {
+        return mDrawableTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setTint(ColorStateList)}} to the image drawable. The default
+     * mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#ImageView_tintMode
+     * @see #setTint(ColorStateList)
+     */
+    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setTint(mDrawableTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the image drawable
+     * @attr ref android.R.styleable#ImageView_tintMode
+     * @see #setTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getTintMode() {
+        return mDrawableTintMode;
+    }
+
+    private void applyDrawableTint() {
+        if (mDrawable != null && mHasDrawableTint) {
+            mDrawable = mDrawable.mutate();
+            mDrawable.setTint(mDrawableTint, mDrawableTintMode);
+        }
+    }
+
+    /**
      * Sets a Bitmap as the content of this ImageView.
      * 
      * @param bm The bitmap to set
@@ -709,17 +805,20 @@
             mDrawable.setCallback(null);
             unscheduleDrawable(mDrawable);
         }
+
         mDrawable = d;
+
         if (d != null) {
             d.setCallback(this);
+            d.setLayoutDirection(getLayoutDirection());
             if (d.isStateful()) {
                 d.setState(getDrawableState());
             }
-            d.setLevel(mLevel);
-            d.setLayoutDirection(getLayoutDirection());
             d.setVisible(getVisibility() == VISIBLE, true);
+            d.setLevel(mLevel);
             mDrawableWidth = d.getIntrinsicWidth();
             mDrawableHeight = d.getIntrinsicHeight();
+            applyDrawableTint();
             applyColorMod();
             configureBounds();
         } else {
@@ -1010,7 +1109,17 @@
         }
     }
 
-    @Override 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mDrawable != null) {
+            mDrawable.setHotspot(x, y);
+        }
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
@@ -1167,6 +1276,7 @@
     public void setColorFilter(ColorFilter cf) {
         if (mColorFilter != cf) {
             mColorFilter = cf;
+            mHasColorFilter = true;
             mColorMod = true;
             applyColorMod();
             invalidate();
@@ -1221,7 +1331,9 @@
         // re-applied if the Drawable is changed.
         if (mDrawable != null && mColorMod) {
             mDrawable = mDrawable.mutate();
-            mDrawable.setColorFilter(mColorFilter);
+            if (mHasColorFilter) {
+                mDrawable.setColorFilter(mColorFilter);
+            }
             mDrawable.setXfermode(mXfermode);
             mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
         }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index b49938c..62a8bec 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,13 +16,17 @@
 
 package android.widget;
 
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
 import com.android.internal.R;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.Animatable;
@@ -210,8 +214,26 @@
     private Transformation mTransformation;
     private AlphaAnimation mAnimation;
     private boolean mHasAnimation;
+
     private Drawable mIndeterminateDrawable;
+    private ColorStateList mIndeterminateTint = null;
+    private PorterDuff.Mode mIndeterminateTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasIndeterminateTint = false;
+
     private Drawable mProgressDrawable;
+
+    private ColorStateList mProgressTint = null;
+    private PorterDuff.Mode mProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasProgressTint = false;
+
+    private ColorStateList mProgressBackgroundTint = null;
+    private PorterDuff.Mode mProgressBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasProgressBackgroundTint = false;
+
+    private ColorStateList mSecondaryProgressTint = null;
+    private PorterDuff.Mode mSecondaryProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasSecondaryProgressTint = false;
+
     private Drawable mCurrentDrawable;
     Bitmap mSampleTile;
     private boolean mNoInvalidate;
@@ -257,11 +279,11 @@
         
         mNoInvalidate = true;
         
-        Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
-        if (drawable != null) {
+        final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
+        if (progressDrawable != null) {
             // Calling this method can set mMaxHeight, make sure the corresponding
             // XML attribute for mMaxHeight is read after calling this method
-            setProgressDrawableTiled(drawable);
+            setProgressDrawableTiled(progressDrawable);
         }
 
 
@@ -288,9 +310,10 @@
         setSecondaryProgress(
                 a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
 
-        drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);
-        if (drawable != null) {
-            setIndeterminateDrawableTiled(drawable);
+        final Drawable indeterminateDrawable = a.getDrawable(
+                R.styleable.ProgressBar_indeterminateDrawable);
+        if (indeterminateDrawable != null) {
+            setIndeterminateDrawableTiled(indeterminateDrawable);
         }
 
         mOnlyIndeterminate = a.getBoolean(
@@ -303,6 +326,53 @@
 
         mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
 
+        if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
+            mProgressTint = a.getColorStateList(
+                    R.styleable.ProgressBar_progressTint);
+            mProgressTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.ProgressBar_progressBackgroundTintMode, -1),
+                    mProgressTintMode);
+            mHasProgressTint = true;
+
+            applyProgressLayerTint(R.id.progress, mProgressTint,
+                    mProgressTintMode, true);
+        }
+
+        if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
+            mProgressBackgroundTint = a.getColorStateList(
+                    R.styleable.ProgressBar_progressBackgroundTint);
+            mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.ProgressBar_progressTintMode, -1),
+                    mProgressBackgroundTintMode);
+            mHasProgressBackgroundTint = true;
+
+            applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+                    mProgressBackgroundTintMode, false);
+        }
+
+        if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
+            mSecondaryProgressTint = a.getColorStateList(
+                    R.styleable.ProgressBar_secondaryProgressTint);
+            mSecondaryProgressTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.ProgressBar_secondaryProgressTintMode, -1),
+                    mSecondaryProgressTintMode);
+            mHasSecondaryProgressTint = true;
+
+            applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+                    mSecondaryProgressTintMode, false);
+        }
+
+        if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
+            mIndeterminateTint = a.getColorStateList(
+                    R.styleable.ProgressBar_indeterminateTint);
+            mIndeterminateTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.ProgressBar_indeterminateTintMode, -1),
+                    mIndeterminateTintMode);
+            mHasIndeterminateTint = true;
+
+            applyIndeterminateTint();
+        }
+
         a.recycle();
 
         // If not explicitly specified this view is important for accessibility.
@@ -479,16 +549,111 @@
      * @see #setIndeterminate(boolean)
      */
     public void setIndeterminateDrawable(Drawable d) {
-        if (d != null) {
-            d.setCallback(this);
+        if (mIndeterminateDrawable != d) {
+            if (mIndeterminateDrawable != null) {
+                mIndeterminateDrawable.setCallback(null);
+                unscheduleDrawable(mIndeterminateDrawable);
+            }
+
+            mIndeterminateDrawable = d;
+
+            if (d != null) {
+                d.setCallback(this);
+                d.setLayoutDirection(getLayoutDirection());
+                if (d.isStateful()) {
+                    d.setState(getDrawableState());
+                }
+                applyIndeterminateTint();
+            }
+
+            if (mIndeterminate) {
+                mCurrentDrawable = d;
+                postInvalidate();
+            }
         }
-        mIndeterminateDrawable = d;
-        if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
-            mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
-        }
-        if (mIndeterminate) {
-            mCurrentDrawable = d;
-            postInvalidate();
+    }
+
+    /**
+     * Applies a tint to the indeterminate drawable.
+     * <p>
+     * Subsequent calls to {@link #setVisibilminateDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and
+     * tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+     * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+     * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+     */
+    private void setIndeterminateTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mIndeterminateTint = tint;
+        mIndeterminateTintMode = tintMode;
+        mHasIndeterminateTint = true;
+
+        applyIndeterminateTint();
+    }
+
+    /**
+     * Applies a tint to the indeterminate drawable. Does not modify the
+     * current tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and
+     * tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+     * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setIndeterminateTint(@Nullable ColorStateList tint) {
+        setIndeterminateTint(tint, mIndeterminateTintMode);
+    }
+
+    /**
+     * @return the tint applied to the indeterminate drawable
+     * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+     * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getIndeterminateTint() {
+        return mIndeterminateTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setIndeterminateTint(ColorStateList)} to the indeterminate
+     * drawable. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+     * @see #setIndeterminateTint(ColorStateList)
+     */
+    public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setIndeterminateTint(mIndeterminateTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the indeterminate drawable
+     * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+     * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getIndeterminateTintMode() {
+        return mIndeterminateTintMode;
+    }
+
+    private void applyIndeterminateTint() {
+        if (mIndeterminateDrawable != null && mHasIndeterminateTint) {
+            mIndeterminateDrawable = mIndeterminateDrawable.mutate();
+            mIndeterminateDrawable.setTint(mIndeterminateTint, mIndeterminateTintMode);
         }
     }
 
@@ -532,42 +697,340 @@
      * @see #setIndeterminate(boolean)
      */
     public void setProgressDrawable(Drawable d) {
-        boolean needUpdate;
-        if (mProgressDrawable != null && d != mProgressDrawable) {
-            mProgressDrawable.setCallback(null);
-            needUpdate = true;
-        } else {
-            needUpdate = false;
-        }
+        if (mProgressDrawable != d) {
+            if (mProgressDrawable != null) {
+                mProgressDrawable.setCallback(null);
+                unscheduleDrawable(mProgressDrawable);
+            }
 
-        if (d != null) {
-            d.setCallback(this);
-            if (canResolveLayoutDirection()) {
+            mProgressDrawable = d;
+
+            if (d != null) {
+                d.setCallback(this);
                 d.setLayoutDirection(getLayoutDirection());
+                if (d.isStateful()) {
+                    d.setState(getDrawableState());
+                }
+
+                // Make sure the ProgressBar is always tall enough
+                int drawableHeight = d.getMinimumHeight();
+                if (mMaxHeight < drawableHeight) {
+                    mMaxHeight = drawableHeight;
+                    requestLayout();
+                }
+
+                if (mHasProgressTint) {
+                    applyProgressLayerTint(R.id.progress, mProgressTint, mProgressTintMode, true);
+                }
+
+                if (mHasProgressBackgroundTint) {
+                    applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+                            mProgressBackgroundTintMode, false);
+                }
+
+                if (mHasSecondaryProgressTint) {
+                    applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+                            mSecondaryProgressTintMode, false);
+                }
             }
 
-            // Make sure the ProgressBar is always tall enough
-            int drawableHeight = d.getMinimumHeight();
-            if (mMaxHeight < drawableHeight) {
-                mMaxHeight = drawableHeight;
-                requestLayout();
+            if (!mIndeterminate) {
+                mCurrentDrawable = d;
+                postInvalidate();
             }
-        }
-        mProgressDrawable = d;
-        if (!mIndeterminate) {
-            mCurrentDrawable = d;
-            postInvalidate();
-        }
 
-        if (needUpdate) {
             updateDrawableBounds(getWidth(), getHeight());
             updateDrawableState();
+
             doRefreshProgress(R.id.progress, mProgress, false, false);
             doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
         }
     }
 
     /**
+     * Applies a tint to the progress indicator, if one exists, or to the
+     * entire progress drawable otherwise.
+     * <p>
+     * The progress indicator should be specified as a layer with
+     * id {@link android.R.id#progress} in a {@link LayerDrawable}
+     * used as the progress drawable.
+     * <p>
+     * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and
+     * tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_progressTint
+     * @attr ref android.R.styleable#ProgressBar_progressTintMode
+     * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+     */
+    private void setProgressTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mProgressTint = tint;
+        mProgressTintMode = tintMode;
+        mHasProgressTint = true;
+
+        applyProgressLayerTint(R.id.progress, tint, tintMode, true);
+    }
+
+    /**
+     * Applies a tint to the progress indicator, if one exists, or to the
+     * entire progress drawable otherwise. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * The progress indicator should be specified as a layer with
+     * id {@link android.R.id#progress} in a {@link LayerDrawable}
+     * used as the progress drawable.
+     * <p>
+     * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and
+     * tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_progressTint
+     * @see #setProgressTint(ColorStateList)
+     */
+    public void setProgressTint(@Nullable ColorStateList tint) {
+        setProgressTint(tint, mProgressTintMode);
+    }
+
+    /**
+     * @return the tint applied to the progress drawable
+     * @attr ref android.R.styleable#ProgressBar_progressTint
+     * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getProgressTint() {
+        return mProgressTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setProgressTint(ColorStateList)}} to the progress
+     * indicator. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#ProgressBar_progressTintMode
+     * @see #setProgressTint(ColorStateList)
+     */
+    public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setProgressTint(mProgressTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the progress drawable
+     * @attr ref android.R.styleable#ProgressBar_progressTintMode
+     * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getProgressTintMode() {
+        return mProgressTintMode;
+    }
+
+    /**
+     * Applies a tint to the progress background, if one exists.
+     * <p>
+     * The progress background must be specified as a layer with
+     * id {@link android.R.id#background} in a {@link LayerDrawable}
+     * used as the progress drawable.
+     * <p>
+     * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+     * drawable contains a progress background will automatically mutate the
+     * drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+     * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+     * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+     */
+    private void setProgressBackgroundTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mProgressBackgroundTint = tint;
+        mProgressBackgroundTintMode = tintMode;
+        mHasProgressBackgroundTint = true;
+
+        applyProgressLayerTint(R.id.background, tint, tintMode, false);
+    }
+
+    /**
+     * Applies a tint to the progress background, if one exists. Does not
+     * modify the current tint mode, which is
+     * {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * The progress background must be specified as a layer with
+     * id {@link android.R.id#background} in a {@link LayerDrawable}
+     * used as the progress drawable.
+     * <p>
+     * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+     * drawable contains a progress background will automatically mutate the
+     * drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+     * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setProgressBackgroundTint(@Nullable ColorStateList tint) {
+        setProgressBackgroundTint(tint, mProgressBackgroundTintMode);
+    }
+
+    /**
+     * @return the tint applied to the progress background
+     * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+     * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getProgressBackgroundTint() {
+        return mProgressBackgroundTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setProgressBackgroundTint(ColorStateList)}} to the progress
+     * background. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+     * @see #setProgressBackgroundTint(ColorStateList)
+     */
+    public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setProgressBackgroundTint(mProgressBackgroundTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the progress
+     *         background
+     * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+     * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getProgressBackgroundTintMode() {
+        return mProgressBackgroundTintMode;
+    }
+
+    /**
+     * Applies a tint to the secondary progress indicator, if one exists.
+     * <p>
+     * The secondary progress indicator must be specified as a layer with
+     * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+     * used as the progress drawable.
+     * <p>
+     * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+     * drawable contains a secondary progress indicator will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+     * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+     * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+     */
+    private void setSecondaryProgressTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mSecondaryProgressTint = tint;
+        mSecondaryProgressTintMode = tintMode;
+        mHasSecondaryProgressTint = true;
+
+        applyProgressLayerTint(R.id.secondaryProgress, tint, tintMode, false);
+    }
+
+    /**
+     * Applies a tint to the secondary progress indicator, if one exists.
+     * Does not modify the current tint mode, which is
+     * {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * The secondary progress indicator must be specified as a layer with
+     * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+     * used as the progress drawable.
+     * <p>
+     * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+     * drawable contains a secondary progress indicator will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+     * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setSecondaryProgressTint(@Nullable ColorStateList tint) {
+        setSecondaryProgressTint(tint, mSecondaryProgressTintMode);
+    }
+
+    /**
+     * @return the tint applied to the secondary progress drawable
+     * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+     * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getSecondaryProgressTint() {
+        return mSecondaryProgressTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setSecondaryProgressTint(ColorStateList)}} to the secondary
+     * progress indicator. The default mode is
+     * {@link PorterDuff.Mode#SRC_ATOP}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+     * @see #setSecondaryProgressTint(ColorStateList)
+     */
+    public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setSecondaryProgressTint(mSecondaryProgressTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the secondary
+     *         progress drawable
+     * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+     * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getSecondaryProgressTintMode() {
+        return mSecondaryProgressTintMode;
+    }
+
+    private void applyProgressLayerTint(int layerId, @Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode, boolean shouldFallback) {
+        final Drawable d = mProgressDrawable;
+        if (d != null) {
+            mProgressDrawable = d.mutate();
+
+            Drawable layer = null;
+            if (d instanceof LayerDrawable) {
+                layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
+            }
+
+            if (shouldFallback && layer == null) {
+                layer = d;
+            }
+
+            if (layer != null) {
+                layer.setTint(tint, tintMode);
+            }
+        }
+    }
+
+    /**
      * Define the tileable drawable used to draw the progress bar in
      * progress mode.
      * <p>
@@ -670,6 +1133,22 @@
         }
     }
 
+    private void setDrawableTint(int id, ColorStateList tint, Mode tintMode, boolean fallback) {
+        Drawable layer = null;
+
+        // We expect a layer drawable, so try to find the target ID.
+        final Drawable d = mCurrentDrawable;
+        if (d instanceof LayerDrawable) {
+            layer = ((LayerDrawable) d).findDrawableByLayerId(id);
+        }
+
+        if (fallback && layer == null) {
+            layer = d;
+        }
+
+        layer.mutate().setTint(tint, tintMode);
+    }
+
     private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
             boolean callBackToApp) {
         float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
@@ -1144,6 +1623,20 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mProgressDrawable != null) {
+            mProgressDrawable.setHotspot(x, y);
+        }
+
+        if (mIndeterminateDrawable != null) {
+            mIndeterminateDrawable.setHotspot(x, y);
+        }
+    }
+
     static class SavedState extends BaseSavedState {
         int progress;
         int secondaryProgress;
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 0c31496..14d782d 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -112,6 +112,16 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mOverlay != null) {
+            mOverlay.setHotspot(x, y);
+        }
+    }
+
     /** This call has no effect anymore, as there is only one QuickContact mode */
     @SuppressWarnings("unused")
     public void setMode(int size) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index c5c6e64..03193a2 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -962,6 +962,20 @@
         invalidate();
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        if (mThumbDrawable != null) {
+            mThumbDrawable.setHotspot(x, y);
+        }
+
+        if (mTrackDrawable != null) {
+            mTrackDrawable.setHotspot(x, y);
+        }
+    }
+
     @Override
     public void invalidateDrawable(Drawable drawable) {
         super.invalidateDrawable(drawable);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 43c8dde..0f51e8b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2551,7 +2551,7 @@
             r = c.getResources();
 
         setRawTextSize(TypedValue.applyDimension(
-            unit, size, r.getDisplayMetrics()));
+                unit, size, r.getDisplayMetrics()));
     }
 
     private void setRawTextSize(float size) {
@@ -2727,7 +2727,6 @@
     /**
      * Sets whether the soft input method will be made visible when this
      * TextView gets focused. The default is true.
-     * @hide
      */
     @android.view.RemotableViewMethod
     public final void setShowSoftInputOnFocus(boolean show) {
@@ -2738,7 +2737,6 @@
     /**
      * Returns whether the soft input method will be made visible when this
      * TextView gets focused. The default is true.
-     * @hide
      */
     public final boolean getShowSoftInputOnFocus() {
         // When there is no Editor, return default true value
@@ -3505,6 +3503,34 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected void setDrawableHotspot(float x, float y) {
+        super.setDrawableHotspot(x, y);
+
+        final Drawables dr = mDrawables;
+        if (dr != null) {
+            if (dr.mDrawableTop != null) {
+                dr.mDrawableTop.setHotspot(x, y);
+            }
+            if (dr.mDrawableBottom != null) {
+                dr.mDrawableBottom.setHotspot(x, y);
+            }
+            if (dr.mDrawableLeft != null) {
+                dr.mDrawableLeft.setHotspot(x, y);
+            }
+            if (dr.mDrawableRight != null) {
+                dr.mDrawableRight.setHotspot(x, y);
+            }
+            if (dr.mDrawableStart != null) {
+                dr.mDrawableStart.setHotspot(x, y);
+            }
+            if (dr.mDrawableEnd != null) {
+                dr.mDrawableEnd.setHotspot(x, y);
+            }
+        }
+    }
+
     @Override
     public Parcelable onSaveInstanceState() {
         Parcelable superState = super.onSaveInstanceState();
@@ -5842,7 +5868,6 @@
                 int end = text.partialEndOffset;
                 if (end > N) end = N;
                 removeParcelableSpans(content, start, end);
-                // If start > end, content.replace will swap them before using them.
                 content.replace(start, end, text.text);
             }
         }
@@ -9035,11 +9060,11 @@
         }
 
         public void drawTextRun(Canvas c, int start, int end,
-                int contextStart, int contextEnd, float x, float y, int flags, Paint p) {
+                int contextStart, int contextEnd, float x, float y, boolean isRtl, Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
-                    contextCount, x, y, flags, p);
+                    contextCount, x, y, isRtl, p);
         }
 
         public float measureText(int start, int end, Paint p) {
@@ -9051,20 +9076,20 @@
         }
 
         public float getTextRunAdvances(int start, int end, int contextStart,
-                int contextEnd, int flags, float[] advances, int advancesIndex,
+                int contextEnd, boolean isRtl, float[] advances, int advancesIndex,
                 Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             return p.getTextRunAdvances(mChars, start + mStart, count,
-                    contextStart + mStart, contextCount, flags, advances,
+                    contextStart + mStart, contextCount, isRtl, advances,
                     advancesIndex);
         }
 
-        public int getTextRunCursor(int contextStart, int contextEnd, int flags,
+        public int getTextRunCursor(int contextStart, int contextEnd, int dir,
                 int offset, int cursorOpt, Paint p) {
             int contextCount = contextEnd - contextStart;
             return p.getTextRunCursor(mChars, contextStart + mStart,
-                    contextCount, flags, offset + mStart, cursorOpt);
+                    contextCount, dir, offset + mStart, cursorOpt);
         }
     }
 
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index cbd9a6a..4f1cd68 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -146,6 +146,8 @@
     private ActionMenuPresenter mOuterActionMenuPresenter;
     private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
 
+    private boolean mCollapsible;
+
     public Toolbar(Context context) {
         this(context, null);
     }
@@ -969,6 +971,23 @@
         return child.getMeasuredWidth() + hMargins;
     }
 
+    /**
+     * Returns true if the Toolbar is collapsible and has no child views with a measured size > 0.
+     */
+    private boolean shouldCollapse() {
+        if (!mCollapsible) return false;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (shouldLayout(child) && child.getMeasuredWidth() > 0 &&
+                    child.getMeasuredHeight() > 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = 0;
@@ -1093,7 +1112,8 @@
         final int measuredHeight = resolveSizeAndState(
                 Math.max(height, getSuggestedMinimumHeight()),
                 heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT);
-        setMeasuredDimension(measuredWidth, measuredHeight);
+
+        setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
     }
 
     @Override
@@ -1490,6 +1510,16 @@
     }
 
     /**
+     * Force the toolbar to collapse to zero-height during measurement if
+     * it could be considered "empty" (no visible elements with nonzero measured size)
+     * @hide
+     */
+    public void setCollapsible(boolean collapsible) {
+        mCollapsible = collapsible;
+        requestLayout();
+    }
+
+    /**
      * Interface responsible for receiving menu item click events if the items themselves
      * do not have individual item click listeners.
      */
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 2b62552..8ee0a1b 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -22,6 +22,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.media.AudioManager;
+import android.media.ClosedCaptionRenderer;
 import android.media.MediaFormat;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
@@ -316,6 +317,7 @@
                     context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
             controller.registerRenderer(new WebVttRenderer(context));
             controller.registerRenderer(new TtmlRenderer(context));
+            controller.registerRenderer(new ClosedCaptionRenderer(context));
             mMediaPlayer.setSubtitleAnchor(controller, this);
 
             if (mAudioSession != 0) {
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index d10451b..643225d 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.backup;
 
+import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -168,12 +169,25 @@
     int startRestore(long token, in PackageInfo[] packages);
 
     /**
-     * Get the package name of the next application with data in the backup store.
-     * @return The name of one of the packages supplied to {@link #startRestore},
-     *   or "" (the empty string) if no more backup data is available,
-     *   or null if an error occurred (the restore should be aborted and rescheduled).
+     * Get the package name of the next application with data in the backup store, plus
+     * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+     * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
+     *
+     * <p>If the package name in the returned RestoreDescription object is the singleton
+     * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+     * in the current restore session: all packages described in startRestore() have been
+     * processed.
+     *
+     * <p>If this method returns {@code null}, it means that a transport-level error has
+     * occurred and the entire restore operation should be abandoned.
+     *
+     * @return A RestoreDescription object containing the name of one of the packages
+     *   supplied to {@link #startRestore} plus an indicator of the data type of that
+     *   restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+     *   no more packages can be restored in this session; or {@code null} to indicate
+     *   a transport-level error.
      */
-    String nextRestorePackage();
+    RestoreDescription nextRestorePackage();
 
     /**
      * Get the data for the application returned by {@link #nextRestorePackage}.
@@ -187,4 +201,59 @@
      * freeing any resources and connections used during the restore process.
      */
     void finishRestore();
+
+    // full backup stuff
+
+    long requestFullBackupTime();
+    int performFullBackup(in PackageInfo targetPackage, in ParcelFileDescriptor socket);
+    int sendBackupData(int numBytes);
+
+    // full restore stuff
+
+    /**
+     * Ask the transport to provide data for the "current" package being restored.  This
+     * is the package that was just reported by {@link #nextRestorePackage()} as having
+     * {@link RestoreDescription#TYPE_FULL_STREAM} data.
+     *
+     * The transport writes some data to the socket supplied to this call, and returns
+     * the number of bytes written.  The system will then read that many bytes and
+     * stream them to the application's agent for restore, then will call this method again
+     * to receive the next chunk of the archive.  This sequence will be repeated until the
+     * transport returns zero indicating that all of the package's data has been delivered
+     * (or returns a negative value indicating some sort of hard error condition at the
+     * transport level).
+     *
+     * <p>After this method returns zero, the system will then call
+     * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+     * application, and the sequence begins again.
+     *
+     * <p>The transport should always close this socket when returning from this method.
+     * Do not cache this socket across multiple calls or you may leak file descriptors.
+     *
+     * @param socket The file descriptor that the transport will use for delivering the
+     *    streamed archive.  The transport must close this socket in all cases when returning
+     *    from this method.
+     * @return 0 when no more data for the current package is available.  A positive value
+     *    indicates the presence of that many bytes to be delivered to the app.  Any negative
+     *    return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+     *    indicating a fatal error condition that precludes further restore operations
+     *    on the current dataset.
+     */
+    int getNextFullRestoreDataChunk(in ParcelFileDescriptor socket);
+
+    /**
+     * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+     * data for restore, it will invoke this method to tell the transport that it should
+     * abandon the data download for the current package.  The OS will then either call
+     * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+     * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+     * operation.
+     *
+     * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+     *    current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+     *    transport-level failure.  If the transport reports an error here, the entire restore
+     *    operation will immediately be finished with no further attempts to restore app data.
+     */
+    int abortFullRestore();
+
 }
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 7292116..ff0ee65 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -19,6 +19,7 @@
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
 import android.content.ComponentName;
 import android.content.Context;
@@ -34,12 +35,17 @@
 
 import com.android.org.bouncycastle.util.encoders.Base64;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
 
 import static android.system.OsConstants.*;
 
@@ -58,22 +64,41 @@
     private static final String TRANSPORT_DESTINATION_STRING
             = "Backing up to debug-only private cache";
 
+    private static final String INCREMENTAL_DIR = "_delta";
+    private static final String FULL_DATA_DIR = "_full";
+
     // The currently-active restore set always has the same (nonzero!) token
     private static final long CURRENT_SET_TOKEN = 1;
 
     private Context mContext;
     private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
     private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
+    private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
+    private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
 
     private PackageInfo[] mRestorePackages = null;
     private int mRestorePackage = -1;  // Index into mRestorePackages
-    private File mRestoreDataDir;
+    private int mRestoreType;
+    private File mRestoreSetDir;
+    private File mRestoreSetIncrementalDir;
+    private File mRestoreSetFullDir;
     private long mRestoreToken;
 
+    // Additional bookkeeping for full backup
+    private String mFullTargetPackage;
+    private ParcelFileDescriptor mSocket;
+    private FileInputStream mSocketInputStream;
+    private BufferedOutputStream mFullBackupOutputStream;
+    private byte[] mFullBackupBuffer;
+
+    private File mFullRestoreSetDir;
+    private HashSet<String> mFullRestorePackages;
 
     public LocalTransport(Context context) {
         mContext = context;
         mCurrentSetDir.mkdirs();
+        mCurrentSetFullDir.mkdir();
+        mCurrentSetIncrementalDir.mkdir();
         if (!SELinux.restorecon(mCurrentSetDir)) {
             Log.e(TAG, "SELinux restorecon failed for " + mCurrentSetDir);
         }
@@ -119,7 +144,7 @@
             }
         }
 
-        File packageDir = new File(mCurrentSetDir, packageInfo.packageName);
+        File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
         packageDir.mkdirs();
 
         // Each 'record' in the restore set is kept in its own file, named by
@@ -200,7 +225,7 @@
     public int clearBackupData(PackageInfo packageInfo) {
         if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
 
-        File packageDir = new File(mCurrentSetDir, packageInfo.packageName);
+        File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
         final File[] fileset = packageDir.listFiles();
         if (fileset != null) {
             for (File f : fileset) {
@@ -208,27 +233,122 @@
             }
             packageDir.delete();
         }
+
+        packageDir = new File(mCurrentSetFullDir, packageInfo.packageName);
+        final File[] tarballs = packageDir.listFiles();
+        if (tarballs != null) {
+            for (File f : tarballs) {
+                f.delete();
+            }
+            packageDir.delete();
+        }
+
         return BackupTransport.TRANSPORT_OK;
     }
 
     public int finishBackup() {
         if (DEBUG) Log.v(TAG, "finishBackup()");
+        if (mSocket != null) {
+            if (DEBUG) {
+                Log.v(TAG, "Concluding full backup of " + mFullTargetPackage);
+            }
+            try {
+                mFullBackupOutputStream.flush();
+                mFullBackupOutputStream.close();
+                mSocketInputStream = null;
+                mFullTargetPackage = null;
+                mSocket.close();
+            } catch (IOException e) {
+                return BackupTransport.TRANSPORT_ERROR;
+            } finally {
+                mSocket = null;
+            }
+        }
         return BackupTransport.TRANSPORT_OK;
     }
 
+    // ------------------------------------------------------------------------------------
+    // Full backup handling
+    public long requestFullBackupTime() {
+        return 0;
+    }
+
+    public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
+        if (mSocket != null) {
+            Log.e(TAG, "Attempt to initiate full backup while one is in progress");
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        if (DEBUG) {
+            Log.i(TAG, "performFullBackup : " + targetPackage);
+        }
+
+        // We know a priori that we run in the system process, so we need to make
+        // sure to dup() our own copy of the socket fd.  Transports which run in
+        // their own processes must not do this.
+        try {
+            mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
+            mSocketInputStream = new FileInputStream(mSocket.getFileDescriptor());
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to process socket for full backup");
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        mFullTargetPackage = targetPackage.packageName;
+        FileOutputStream tarstream;
+        try {
+            File tarball = new File(mCurrentSetFullDir, mFullTargetPackage);
+            tarstream = new FileOutputStream(tarball);
+        } catch (FileNotFoundException e) {
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+        mFullBackupOutputStream = new BufferedOutputStream(tarstream);
+        mFullBackupBuffer = new byte[4096];
+
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    public int sendBackupData(int numBytes) {
+        if (mFullBackupBuffer == null) {
+            Log.w(TAG, "Attempted sendBackupData before performFullBackup");
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        if (numBytes > mFullBackupBuffer.length) {
+            mFullBackupBuffer = new byte[numBytes];
+        }
+        while (numBytes > 0) {
+            try {
+            int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, numBytes);
+            if (nRead < 0) {
+                // Something went wrong if we expect data but saw EOD
+                Log.w(TAG, "Unexpected EOD; failing backup");
+                return BackupTransport.TRANSPORT_ERROR;
+            }
+            mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
+            numBytes -= nRead;
+            } catch (IOException e) {
+                Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
+                return BackupTransport.TRANSPORT_ERROR;
+            }
+        }
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    // ------------------------------------------------------------------------------------
     // Restore handling
     static final long[] POSSIBLE_SETS = { 2, 3, 4, 5, 6, 7, 8, 9 }; 
     public RestoreSet[] getAvailableRestoreSets() {
         long[] existing = new long[POSSIBLE_SETS.length + 1];
         int num = 0;
 
-        // see which possible non-current sets exist, then put the current set at the end
+        // see which possible non-current sets exist...
         for (long token : POSSIBLE_SETS) {
             if ((new File(mDataDir, Long.toString(token))).exists()) {
                 existing[num++] = token;
             }
         }
-        // and always the currently-active set last
+        // ...and always the currently-active set last
         existing[num++] = CURRENT_SET_TOKEN;
 
         RestoreSet[] available = new RestoreSet[num];
@@ -248,30 +368,55 @@
         mRestorePackages = packages;
         mRestorePackage = -1;
         mRestoreToken = token;
-        mRestoreDataDir = new File(mDataDir, Long.toString(token));
+        mRestoreSetDir = new File(mDataDir, Long.toString(token));
+        mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR);
+        mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR);
         return BackupTransport.TRANSPORT_OK;
     }
 
-    public String nextRestorePackage() {
+    @Override
+    public RestoreDescription nextRestorePackage() {
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+
+        boolean found = false;
         while (++mRestorePackage < mRestorePackages.length) {
             String name = mRestorePackages[mRestorePackage].packageName;
+
+            // If we have key/value data for this package, deliver that
             // skip packages where we have a data dir but no actual contents
-            String[] contents = (new File(mRestoreDataDir, name)).list();
+            String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
             if (contents != null && contents.length > 0) {
-                if (DEBUG) Log.v(TAG, "  nextRestorePackage() = " + name);
-                return name;
+                if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+                mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
+                found = true;
+            }
+
+            if (!found) {
+                // No key/value data; check for [non-empty] full data
+                File maybeFullData = new File(mRestoreSetFullDir, name);
+                if (maybeFullData.length() > 0) {
+                    if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) = " + name);
+                    mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
+                    found = true;
+                }
+            }
+
+            if (found) {
+                return new RestoreDescription(name, mRestoreType);
             }
         }
 
         if (DEBUG) Log.v(TAG, "  no more packages to restore");
-        return "";
+        return RestoreDescription.NO_MORE_PACKAGES;
     }
 
     public int getRestoreData(ParcelFileDescriptor outFd) {
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
         if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
-        File packageDir = new File(mRestoreDataDir, mRestorePackages[mRestorePackage].packageName);
+        if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) {
+            throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset");
+        }
+        File packageDir = new File(mRestoreSetDir, mRestorePackages[mRestorePackage].packageName);
 
         // The restore set is the concatenation of the individual record blobs,
         // each of which is a file in the package's directory.  We return the
@@ -345,4 +490,60 @@
     public void finishRestore() {
         if (DEBUG) Log.v(TAG, "finishRestore()");
     }
+
+    // ------------------------------------------------------------------------------------
+    // Full restore handling
+
+    public int prepareFullRestore(long token, String[] targetPackages) {
+        mRestoreSetDir = new File(mDataDir, Long.toString(token));
+        mFullRestoreSetDir = new File(mRestoreSetDir, FULL_DATA_DIR);
+        mFullRestorePackages = new HashSet<String>();
+        if (mFullRestoreSetDir.exists()) {
+            List<String> pkgs = Arrays.asList(mFullRestoreSetDir.list());
+            HashSet<String> available = new HashSet<String>(pkgs);
+
+            for (int i = 0; i < targetPackages.length; i++) {
+                if (available.contains(targetPackages[i])) {
+                    mFullRestorePackages.add(targetPackages[i]);
+                }
+            }
+        }
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    /**
+     * Ask the transport what package's full data will be restored next.  When all apps'
+     * data has been delivered, the transport should return {@code null} here.
+     * @return The package name of the next application whose data will be restored, or
+     *    {@code null} if all available package has been delivered.
+     */
+    public String getNextFullRestorePackage() {
+        return null;
+    }
+
+    /**
+     * Ask the transport to provide data for the "current" package being restored.  The
+     * transport then writes some data to the socket supplied to this call, and returns
+     * the number of bytes written.  The system will then read that many bytes and
+     * stream them to the application's agent for restore, then will call this method again
+     * to receive the next chunk of the archive.  This sequence will be repeated until the
+     * transport returns zero indicating that all of the package's data has been delivered
+     * (or returns a negative value indicating some sort of hard error condition at the
+     * transport level).
+     *
+     * <p>After this method returns zero, the system will then call
+     * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+     * application, and the sequence begins again.
+     *
+     * @param socket The file descriptor that the transport will use for delivering the
+     *    streamed archive.
+     * @return 0 when no more data for the current package is available.  A positive value
+     *    indicates the presence of that much data to be delivered to the app.  A negative
+     *    return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+     *    indicating a fatal error condition that precludes further restore operations
+     *    on the current dataset.
+     */
+    public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+        return 0;
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 8a9cb22..ea36e37 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -246,6 +247,13 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        init(getContext());
+        requestApplyInsets();
+    }
+
+    @Override
     public void onWindowSystemUiVisibilityChanged(int visible) {
         super.onWindowSystemUiVisibilityChanged(visible);
         pullChildren();
@@ -329,7 +337,7 @@
         // insets in all cases, we need to know the measured size of the various action
         // bar elements.  onApplyWindowInsets() happens before the measure pass, so we can't
         // do that here.  Instead we will take this up in onMeasure().
-        return WindowInsets.EMPTY;
+        return WindowInsets.CONSUMED;
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index b298d85..7fb2efd 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -424,7 +424,7 @@
 
     @Override
     public void setCollapsible(boolean collapsible) {
-        // Ignore
+        mToolbar.setCollapsible(collapsible);
     }
 
     @Override
@@ -480,7 +480,7 @@
 
     private void ensureSpinner() {
         if (mSpinner == null) {
-            mSpinner = new Spinner(getContext());
+            mSpinner = new Spinner(getContext(), null, R.attr.actionDropDownStyle);
             Toolbar.LayoutParams lp = new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
             mSpinner.setLayoutParams(lp);
@@ -569,7 +569,7 @@
 
     @Override
     public void setNavigationIcon(int resId) {
-        setNavigationIcon(mToolbar.getContext().getDrawable(resId));
+        setNavigationIcon(resId != 0 ? mToolbar.getContext().getDrawable(resId) : null);
     }
 
     @Override
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 430dd63..3d9fb5c 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -18,6 +18,7 @@
 
 import android.net.INetworkManagementEventObserver;
 import android.net.LinkAddress;
+import android.net.RouteInfo;
 
 /**
  * Base {@link INetworkManagementEventObserver} that provides no-op
@@ -70,4 +71,14 @@
     public void interfaceDnsServerInfo(String iface, long lifetime, String[] servers) {
         // default no-op
     }
+
+    @Override
+    public void routeUpdated(RouteInfo route) {
+        // default no-op
+    }
+
+    @Override
+    public void routeRemoved(RouteInfo route) {
+        // default no-op
+    }
 }
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
new file mode 100644
index 0000000..7dd8dd8
--- /dev/null
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -0,0 +1,161 @@
+/*
+ * 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.net;
+
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
+import android.util.Log;
+
+/**
+ * Keeps track of link configuration received from Netlink.
+ *
+ * Instances of this class are expected to be owned by subsystems such as Wi-Fi
+ * or Ethernet that manage one or more network interfaces. Each interface to be
+ * tracked needs its own {@code NetlinkTracker}.
+ *
+ * An instance of this class is constructed by passing in an interface name and
+ * a callback. The owner is then responsible for registering the tracker with
+ * NetworkManagementService. When the class receives update notifications from
+ * the NetworkManagementService notification threads, it applies the update to
+ * its local LinkProperties, and if something has changed, notifies its owner of
+ * the update via the callback.
+ *
+ * The owner can then call {@code getLinkProperties()} in order to find out
+ * what changed. If in the meantime the LinkProperties stored here have changed,
+ * this class will return the current LinkProperties. Because each change
+ * triggers an update callback after the change is made, the owner may get more
+ * callbacks than strictly necessary (some of which may be no-ops), but will not
+ * be out of sync once all callbacks have been processed.
+ *
+ * Threading model:
+ *
+ * - The owner of this class is expected to create it, register it, and call
+ *   getLinkProperties or clearLinkProperties on its thread.
+ * - Most of the methods in the class are inherited from BaseNetworkObserver
+ *   and are called by NetworkManagementService notification threads.
+ * - All accesses to mLinkProperties must be synchronized(this). All the other
+ *   member variables are immutable once the object is constructed.
+ *
+ * This class currently tracks IPv4 and IPv6 addresses. In the future it will
+ * track routes and DNS servers.
+ *
+ * @hide
+ */
+public class NetlinkTracker extends BaseNetworkObserver {
+
+    private final String TAG;
+
+    public interface Callback {
+        public void update();
+    }
+
+    private final String mInterfaceName;
+    private final Callback mCallback;
+    private final LinkProperties mLinkProperties;
+
+    private static final boolean DBG = true;
+
+    public NetlinkTracker(String iface, Callback callback) {
+        TAG = "NetlinkTracker/" + iface;
+        mInterfaceName = iface;
+        mCallback = callback;
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+    }
+
+    private void maybeLog(String operation, String iface, LinkAddress address) {
+        if (DBG) {
+            Log.d(TAG, operation + ": " + address + " on " + iface +
+                    " flags " + address.getFlags() + " scope " + address.getScope());
+        }
+    }
+
+    private void maybeLog(String operation, Object o) {
+        if (DBG) {
+            Log.d(TAG, operation + ": " + o.toString());
+        }
+    }
+
+    @Override
+    public void addressUpdated(String iface, LinkAddress address) {
+        if (mInterfaceName.equals(iface)) {
+            maybeLog("addressUpdated", iface, address);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.addLinkAddress(address);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void addressRemoved(String iface, LinkAddress address) {
+        if (mInterfaceName.equals(iface)) {
+            maybeLog("addressRemoved", iface, address);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.removeLinkAddress(address);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void routeUpdated(RouteInfo route) {
+        if (mInterfaceName.equals(route.getInterface())) {
+            maybeLog("routeUpdated", route);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.addRoute(route);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void routeRemoved(RouteInfo route) {
+        if (mInterfaceName.equals(route.getInterface())) {
+            maybeLog("routeRemoved", route);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.removeRoute(route);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    /**
+     * Returns a copy of this object's LinkProperties.
+     */
+    public synchronized LinkProperties getLinkProperties() {
+        return new LinkProperties(mLinkProperties);
+    }
+
+    public synchronized void clearLinkProperties() {
+        mLinkProperties.clear();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index de46804..15dfed1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -89,6 +89,7 @@
 	android_util_Process.cpp \
 	android_util_StringBlock.cpp \
 	android_util_XmlBlock.cpp \
+	android/graphics/AndroidPicture.cpp \
 	android/graphics/AutoDecodeCancel.cpp \
 	android/graphics/Bitmap.cpp \
 	android/graphics/BitmapFactory.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f8e6bc3..a7a1faad 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -159,6 +159,7 @@
 extern int register_android_text_AndroidCharacter(JNIEnv *env);
 extern int register_android_text_AndroidBidi(JNIEnv *env);
 extern int register_android_opengl_classes(JNIEnv *env);
+extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
 extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
 extern int register_android_server_Watchdog(JNIEnv* env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -244,9 +245,6 @@
         mArgBlockLength(argBlockLength)
 {
     SkGraphics::Init();
-    // this sets our preference for 16bit images during decode
-    // in case the src is opaque and 24bit
-    SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config);
     // There is also a global font cache, but its budget is specified in code
     // see SkFontHost_android.cpp
 
@@ -825,8 +823,9 @@
             mOptions.add(opt);
         }
 
-        // Whether the profile should start upon app startup or be delayed by some random offset.
-        property_get("dalvik.vm.profile.start-immediately", propBuf, "0");
+        // Whether the profile should start upon app startup or be delayed by some random offset
+        // (in seconds) that is bound between 0 and a fixed value.
+        property_get("dalvik.vm.profile.start-immed", propBuf, "0");
         if (propBuf[0] == '1') {
             opt.optionString = "-Xprofile-start-immediately";
             mOptions.add(opt);
@@ -1330,6 +1329,7 @@
     REG_JNI(register_android_media_ToneGenerator),
 
     REG_JNI(register_android_opengl_classes),
+	REG_JNI(register_android_server_fingerprint_FingerprintService),
     REG_JNI(register_android_server_NetworkManagementSocketTagger),
     REG_JNI(register_android_server_Watchdog),
     REG_JNI(register_android_ddm_DdmHandleNativeHeap),
diff --git a/core/jni/android/graphics/AndroidPicture.cpp b/core/jni/android/graphics/AndroidPicture.cpp
new file mode 100644
index 0000000..5977ab2
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.cpp
@@ -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.
+ */
+
+#include "AndroidPicture.h"
+#include "SkCanvas.h"
+#include "SkStream.h"
+
+AndroidPicture::AndroidPicture(const AndroidPicture* src) {
+    if (NULL != src) {
+        mWidth = src->width();
+        mHeight = src->height();
+        if (NULL != src->mPicture.get()) {
+            mPicture.reset(SkRef(src->mPicture.get()));
+        } if (NULL != src->mRecorder.get()) {
+            mPicture.reset(src->makePartialCopy());
+        }
+    } else {
+        mWidth = 0;
+        mHeight = 0;
+    }
+}
+
+SkCanvas* AndroidPicture::beginRecording(int width, int height) {
+    mPicture.reset(NULL);
+    mRecorder.reset(new SkPictureRecorder);
+    mWidth = width;
+    mHeight = height;
+    return mRecorder->beginRecording(width, height, NULL, 0);
+}
+
+void AndroidPicture::endRecording() {
+    if (NULL != mRecorder.get()) {
+        mPicture.reset(mRecorder->endRecording());
+        mRecorder.reset(NULL);
+    }
+}
+
+int AndroidPicture::width() const {
+    if (NULL != mPicture.get()) {
+        SkASSERT(mPicture->width() == mWidth);
+        SkASSERT(mPicture->height() == mHeight);
+    }
+
+    return mWidth;
+}
+
+int AndroidPicture::height() const {
+    if (NULL != mPicture.get()) {
+        SkASSERT(mPicture->width() == mWidth);
+        SkASSERT(mPicture->height() == mHeight);
+    }
+
+    return mHeight;
+}
+
+AndroidPicture* AndroidPicture::CreateFromStream(SkStream* stream) {
+    AndroidPicture* newPict = new AndroidPicture;
+
+    newPict->mPicture.reset(SkPicture::CreateFromStream(stream));
+    if (NULL != newPict->mPicture.get()) {
+        newPict->mWidth = newPict->mPicture->width();
+        newPict->mHeight = newPict->mPicture->height();
+    }
+
+    return newPict;
+}
+
+void AndroidPicture::serialize(SkWStream* stream) const {
+    if (NULL != mRecorder.get()) {
+        SkAutoTDelete<SkPicture> tempPict(this->makePartialCopy());
+        tempPict->serialize(stream);
+    } else if (NULL != mPicture.get()) {
+        mPicture->serialize(stream);
+    } else {
+        SkPicture empty;
+        empty.serialize(stream);
+    }
+}
+
+void AndroidPicture::draw(SkCanvas* canvas) {
+    if (NULL != mRecorder.get()) {
+        this->endRecording();
+        SkASSERT(NULL != mPicture.get());
+    }
+    if (NULL != mPicture.get()) {
+        // TODO: remove this const_cast once pictures are immutable
+        const_cast<SkPicture*>(mPicture.get())->draw(canvas);
+    }
+}
+
+SkPicture* AndroidPicture::makePartialCopy() const {
+    SkASSERT(NULL != mRecorder.get());
+
+    SkPictureRecorder reRecorder;
+
+    SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+    mRecorder->partialReplay(canvas);
+    return reRecorder.endRecording();
+}
diff --git a/core/jni/android/graphics/AndroidPicture.h b/core/jni/android/graphics/AndroidPicture.h
new file mode 100644
index 0000000..f434941
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PICTURE_H
+#define ANDROID_PICTURE_H
+
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkRefCnt.h"
+#include "SkTemplates.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPictureRecorder;
+class SkStream;
+class SkWStream;
+
+// Skia's SkPicture class has been split into an SkPictureRecorder
+// and an SkPicture. AndroidPicture recreates the functionality
+// of the old SkPicture interface by flip-flopping between the two
+// new classes.
+class AndroidPicture {
+public:
+    explicit AndroidPicture(const AndroidPicture* src = NULL);
+
+    SkCanvas* beginRecording(int width, int height);
+
+    void endRecording();
+
+    int width() const;
+
+    int height() const;
+
+    static AndroidPicture* CreateFromStream(SkStream* stream);
+
+    void serialize(SkWStream* stream) const;
+
+    void draw(SkCanvas* canvas);
+
+private:
+    int mWidth;
+    int mHeight;
+    SkAutoTUnref<const SkPicture> mPicture;
+    SkAutoTDelete<SkPictureRecorder> mRecorder;
+
+    // Make a copy of a picture that is in the midst of being recorded. The
+    // resulting picture will have balanced saves and restores.
+    SkPicture* makePartialCopy() const;
+};
+#endif // ANDROID_PICTURE_H
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0328517..9998995 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -361,24 +361,50 @@
 }
 
 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
-        jint width, jint height, jint configHandle, jint allocSize) {
+        jint width, jint height, jint configHandle, jint allocSize,
+        jboolean requestPremul) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
-    if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+    SkColorType colorType = SkBitmapConfigToColorType(config);
+
+    // ARGB_4444 is a deprecated format, convert automatically to 8888
+    if (colorType == kARGB_4444_SkColorType) {
+        colorType = kN32_SkColorType;
+    }
+
+    if (width * height * SkColorTypeBytesPerPixel(colorType) > 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);
+    ref->ref();
+    SkAlphaType alphaType;
+    if (bitmap->colorType() != kRGB_565_SkColorType
+            && bitmap->alphaType() == kOpaque_SkAlphaType) {
+        // If the original bitmap was set to opaque, keep that setting, unless it
+        // was 565, which is required to be opaque.
+        alphaType = kOpaque_SkAlphaType;
+    } else {
+        // Otherwise respect the premultiplied request.
+        alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
+    }
+    bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
+    // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for
+    // its alphatype), so it would make more sense from Skia's perspective to create a
+    // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key
+    // for its cache, so it won't realize this is the same Java Bitmap.
+    SkImageInfo& info = const_cast<SkImageInfo&>(ref->info());
+    // Use the updated from the SkBitmap, which may have corrected an invalid alphatype.
+    // (e.g. 565 non-opaque)
+    info = bitmap->info();
     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.
+    // colortype and alphatype) has changed.
     ref->notifyPixelsChanged();
-    SkSafeUnref(ref);
+    ref->unref();
 }
 
 // These must match the int values in Bitmap.java
@@ -799,7 +825,7 @@
         (void*)Bitmap_copy },
     {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
-    {   "nativeReconfigure",        "(JIIII)V", (void*)Bitmap_reconfigure },
+    {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
         (void*)Bitmap_compress },
     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3b44f97..4584c46 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -19,11 +19,14 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include "SkCanvas.h"
+#include "SkClipStack.h"
 #include "SkDevice.h"
+#include "SkDeque.h"
 #include "SkDrawFilter.h"
 #include "SkGraphics.h"
 #include "SkPorterDuff.h"
 #include "SkShader.h"
+#include "SkTArray.h"
 #include "SkTemplates.h"
 
 #ifdef USE_MINIKIN
@@ -43,25 +46,6 @@
 
 namespace android {
 
-// Holds an SkCanvas reference plus additional native data.
-class NativeCanvasWrapper {
-public:
-    NativeCanvasWrapper(SkCanvas* canvas)
-        : mCanvas(canvas) { }
-
-    SkCanvas* getCanvas() const {
-        return mCanvas.get();
-    }
-
-    void setCanvas(SkCanvas* canvas) {
-        SkASSERT(canvas);
-        mCanvas.reset(canvas);
-    }
-
-private:
-    SkAutoTUnref<SkCanvas> mCanvas;
-};
-
 class ClipCopier : public SkCanvas::ClipVisitor {
 public:
     ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
@@ -80,6 +64,155 @@
     SkCanvas* m_dstCanvas;
 };
 
+// Holds an SkCanvas reference plus additional native data.
+class NativeCanvasWrapper {
+private:
+    struct SaveRec {
+        int                 saveCount;
+        SkCanvas::SaveFlags saveFlags;
+    };
+
+public:
+    NativeCanvasWrapper(SkCanvas* canvas)
+        : mCanvas(canvas)
+        , mSaveStack(NULL) {
+        SkASSERT(canvas);
+    }
+
+    ~NativeCanvasWrapper() {
+        delete mSaveStack;
+    }
+
+    SkCanvas* getCanvas() const {
+        return mCanvas.get();
+    }
+
+    void setCanvas(SkCanvas* canvas) {
+        SkASSERT(canvas);
+        mCanvas.reset(canvas);
+
+        delete mSaveStack;
+        mSaveStack = NULL;
+    }
+
+    int save(SkCanvas::SaveFlags flags) {
+        int count = mCanvas->save();
+        recordPartialSave(flags);
+        return count;
+    }
+
+    int saveLayer(const SkRect* bounds, const SkPaint* paint,
+                            SkCanvas::SaveFlags flags) {
+        int count = mCanvas->saveLayer(bounds, paint,
+                static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag));
+        recordPartialSave(flags);
+        return count;
+    }
+
+    int saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
+                       SkCanvas::SaveFlags flags) {
+        int count = mCanvas->saveLayerAlpha(bounds, alpha,
+                static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag));
+        recordPartialSave(flags);
+        return count;
+    }
+
+    void restore() {
+        const SaveRec* rec = (NULL == mSaveStack)
+                ? NULL
+                : static_cast<SaveRec*>(mSaveStack->back());
+        int currentSaveCount = mCanvas->getSaveCount() - 1;
+        SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount);
+
+        if (NULL == rec || rec->saveCount != currentSaveCount) {
+            // Fast path - no record for this frame.
+            mCanvas->restore();
+            return;
+        }
+
+        bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag);
+        bool preserveClip   = !(rec->saveFlags & SkCanvas::kClip_SaveFlag);
+
+        SkMatrix savedMatrix;
+        if (preserveMatrix) {
+            savedMatrix = mCanvas->getTotalMatrix();
+        }
+
+        SkTArray<SkClipStack::Element> savedClips;
+        if (preserveClip) {
+            saveClipsForFrame(savedClips, currentSaveCount);
+        }
+
+        mCanvas->restore();
+
+        if (preserveMatrix) {
+            mCanvas->setMatrix(savedMatrix);
+        }
+
+        if (preserveClip && !savedClips.empty()) {
+            applyClips(savedClips);
+        }
+
+        mSaveStack->pop_back();
+    }
+
+private:
+    void recordPartialSave(SkCanvas::SaveFlags flags) {
+        // A partial save is a save operation which doesn't capture the full canvas state.
+        // (either kMatrix_SaveFlags or kClip_SaveFlag is missing).
+
+        // Mask-out non canvas state bits.
+        flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag);
+
+        if (SkCanvas::kMatrixClip_SaveFlag == flags) {
+            // not a partial save.
+            return;
+        }
+
+        if (NULL == mSaveStack) {
+            mSaveStack = new SkDeque(sizeof(struct SaveRec), 8);
+        }
+
+        SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
+        // Store the save counter in the SkClipStack domain.
+        // (0-based, equal to the number of save ops on the stack).
+        rec->saveCount = mCanvas->getSaveCount() - 1;
+        rec->saveFlags = flags;
+    }
+
+    void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips,
+                           int frameSaveCount) {
+        SkClipStack::Iter clipIterator(*mCanvas->getClipStack(),
+                                       SkClipStack::Iter::kTop_IterStart);
+        while (const SkClipStack::Element* elem = clipIterator.next()) {
+            if (elem->getSaveCount() < frameSaveCount) {
+                // done with the current frame.
+                break;
+            }
+            SkASSERT(elem->getSaveCount() == frameSaveCount);
+            clips.push_back(*elem);
+        }
+    }
+
+    void applyClips(const SkTArray<SkClipStack::Element>& clips) {
+        ClipCopier clipCopier(mCanvas);
+
+        // The clip stack stores clips in device space.
+        SkMatrix origMatrix = mCanvas->getTotalMatrix();
+        mCanvas->resetMatrix();
+
+        // We pushed the clips in reverse order.
+        for (int i = clips.count() - 1; i >= 0; --i) {
+            clips[i].replay(&clipCopier);
+        }
+
+        mCanvas->setMatrix(origMatrix);
+    }
+
+    SkAutoTUnref<SkCanvas> mCanvas;
+    SkDeque* mSaveStack; // lazily allocated, tracks partial saves.
+};
+
 // Returns true if the SkCanvas's clip is non-empty.
 static jboolean hasNonEmptyClip(const SkCanvas& canvas) {
     bool emptyClip = canvas.isClipEmpty();
@@ -88,11 +221,15 @@
 
 class SkCanvasGlue {
 public:
+    // Get the native wrapper for a given handle.
+    static inline NativeCanvasWrapper* getNativeWrapper(jlong nativeHandle) {
+        SkASSERT(nativeHandle);
+        return reinterpret_cast<NativeCanvasWrapper*>(nativeHandle);
+    }
 
     // Get the SkCanvas for a given native handle.
     static inline SkCanvas* getNativeCanvas(jlong nativeHandle) {
-        SkASSERT(nativeHandle);
-        NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle);
+        NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle);
         SkCanvas* canvas = wrapper->getCanvas();
         SkASSERT(canvas);
 
@@ -186,56 +323,56 @@
     }
 
     static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
-        SkCanvas* canvas = getNativeCanvas(canvasHandle);
+        NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
         SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
-        return static_cast<jint>(canvas->save(flags));
+        return static_cast<jint>(wrapper->save(flags));
     }
 
     static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle,
                           jfloat l, jfloat t, jfloat r, jfloat b,
-                          jlong paintHandle, jint flags) {
-        SkCanvas* canvas = getNativeCanvas(canvasHandle);
+                          jlong paintHandle, jint flagsHandle) {
+        NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
         SkPaint* paint  = reinterpret_cast<SkPaint*>(paintHandle);
+        SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
         SkRect bounds;
         bounds.set(l, t, r, b);
-        int result = canvas->saveLayer(&bounds, paint,
-                                      static_cast<SkCanvas::SaveFlags>(flags));
-        return static_cast<jint>(result);
+        return static_cast<jint>(wrapper->saveLayer(&bounds, paint, flags));
     }
 
     static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle,
                                jfloat l, jfloat t, jfloat r, jfloat b,
-                               jint alpha, jint flags) {
-        SkCanvas* canvas = getNativeCanvas(canvasHandle);
+                               jint alpha, jint flagsHandle) {
+        NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
+        SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
         SkRect  bounds;
         bounds.set(l, t, r, b);
-        int result = canvas->saveLayerAlpha(&bounds, alpha,
-                                      static_cast<SkCanvas::SaveFlags>(flags));
-        return static_cast<jint>(result);
+        return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags));
     }
 
     static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
-        SkCanvas* canvas = getNativeCanvas(canvasHandle);
-        if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
+        NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
+        if (wrapper->getCanvas()->getSaveCount() <= 1) {  // cannot restore anymore
             doThrowISE(env, "Underflow in restore");
             return;
         }
-        canvas->restore();
+        wrapper->restore();
     }
 
     static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
-        SkCanvas* canvas = getNativeCanvas(canvasHandle);
-        return static_cast<jint>(canvas->getSaveCount());
+        return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount());
     }
 
     static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle,
                                jint restoreCount) {
-        SkCanvas* canvas = getNativeCanvas(canvasHandle);
+        NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
         if (restoreCount < 1) {
             doThrowIAE(env, "Underflow in restoreToCount");
             return;
         }
-        canvas->restoreToCount(restoreCount);
+
+        while (wrapper->getCanvas()->getSaveCount() > restoreCount) {
+            wrapper->restore();
+        }
     }
 
     static void translate(JNIEnv*, jobject, jlong canvasHandle,
@@ -432,12 +569,11 @@
         canvas->drawRectCoords(left, top, right, bottom, *paint);
     }
 
-    static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jobject joval,
-                         jlong paintHandle) {
+    static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
+            jfloat right, jfloat bottom, jlong paintHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
-        SkRect oval;
-        GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+        SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
         canvas->drawOval(oval, *paint);
     }
 
@@ -448,13 +584,12 @@
         canvas->drawCircle(cx, cy, radius, *paint);
     }
 
-    static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jobject joval,
-                        jfloat startAngle, jfloat sweepAngle,
-                        jboolean useCenter, jlong paintHandle) {
+    static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
+            jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, jboolean useCenter,
+            jlong paintHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
-        SkRect oval;
-        GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+        SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
         canvas->drawArc(oval, startAngle, sweepAngle, useCenter, *paint);
     }
 
@@ -745,26 +880,26 @@
 
     static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle,
                                                jcharArray text, jint index, jint count,
-                                               jfloat x, jfloat y, jint flags,
+                                               jfloat x, jfloat y, jint bidiFlags,
                                                jlong paintHandle, jlong typefaceHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint, typeface);
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, bidiFlags, paint, typeface);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
     static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject,
                                                    jlong canvasHandle, jstring text,
                                                    jint start, jint end,
-                                                   jfloat x, jfloat y, jint flags,
+                                                   jfloat x, jfloat y, jint bidiFlags,
                                                    jlong paintHandle, jlong typefaceHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint, typeface);
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, bidiFlags, paint, typeface);
         env->ReleaseStringChars(text, textArray);
     }
 
@@ -814,24 +949,25 @@
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
-            jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+            jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 
         jint count = end - start;
-        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint, typeface);
+        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, bidiFlags, paint,
+                typeface);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int count, int contextCount,
-            jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+            jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 
 #ifdef USE_MINIKIN
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(textArray, start, count, contextCount, css);
         drawGlyphsToSkia(canvas, paint, layout, x, y);
 #else
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                textArray, start, count, contextCount, flags);
+                textArray, start, count, contextCount, bidiFlags);
         if (value == NULL) {
             return;
         }
@@ -842,7 +978,8 @@
             x -= value->getTotalAdvance();
         }
         paint->setTextAlign(SkPaint::kLeft_Align);
-        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
+        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(),
+                x, y, paint);
         doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
         paint->setTextAlign(align);
 #endif
@@ -853,42 +990,37 @@
 #define kStdUnderline_Offset    (1.0f / 9.0f)
 #define kStdUnderline_Thickness (1.0f / 18.0f)
 
-static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) {
-    uint32_t flags;
-    SkDrawFilter* drawFilter = canvas->getDrawFilter();
-    if (drawFilter) {
-        SkPaint paintCopy(*paint);
-        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
-        flags = paintCopy.getFlags();
-    } else {
-        flags = paint->getFlags();
-    }
-    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
-        SkScalar left = x;
-        SkScalar right = x + length;
-        float textSize = paint->getTextSize();
-        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
-        if (flags & SkPaint::kUnderlineText_Flag) {
-            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
-            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
-            canvas->drawRectCoords(left, top, right, bottom, *paint);
+    static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length,
+            SkPaint* paint) {
+        uint32_t flags;
+        SkDrawFilter* drawFilter = canvas->getDrawFilter();
+        if (drawFilter) {
+            SkPaint paintCopy(*paint);
+            drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
+            flags = paintCopy.getFlags();
+        } else {
+            flags = paint->getFlags();
         }
-        if (flags & SkPaint::kStrikeThruText_Flag) {
-            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
-            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
-            canvas->drawRectCoords(left, top, right, bottom, *paint);
+        if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
+            SkScalar left = x;
+            SkScalar right = x + length;
+            float textSize = paint->getTextSize();
+            float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
+            if (flags & SkPaint::kUnderlineText_Flag) {
+                SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
+                SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
+                canvas->drawRectCoords(left, top, right, bottom, *paint);
+            }
+            if (flags & SkPaint::kStrikeThruText_Flag) {
+                SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
+                SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
+                canvas->drawRectCoords(left, top, right, bottom, *paint);
+            }
         }
     }
-}
-
-    static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
-        // Beware: this needs Glyph encoding (already done on the Paint constructor)
-        canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
-    }
 
     static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
-            int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
+            int index, int count, jfloat x, jfloat y, SkPaint* paint) {
         SkPoint* posPtr = new SkPoint[count];
         for (int indx = 0; indx < count; indx++) {
             posPtr[indx].fX = x + posArray[indx * 2];
@@ -898,33 +1030,35 @@
         delete[] posPtr;
     }
 
-    static void drawTextRun___CIIIIFFIPaintTypeface(
+    static void drawTextRun___CIIIIFFZPaintTypeface(
             JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
             jint count, jint contextIndex, jint contextCount,
-            jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) {
+            jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
 
+        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
-                count, contextCount, x, y, dirFlags, paint, typeface);
+                count, contextCount, x, y, bidiFlags, paint, typeface);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
-    static void drawTextRun__StringIIIIFFIPaintTypeface(
+    static void drawTextRun__StringIIIIFFZPaintTypeface(
             JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, jint start,
             jint end, jint contextStart, jint contextEnd,
-            jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) {
+            jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
 
+        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
-                count, contextCount, x, y, dirFlags, paint, typeface);
+                count, contextCount, x, y, bidiFlags, paint, typeface);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -1105,11 +1239,9 @@
     {"native_drawLines", "(J[FIIJ)V", (void*) SkCanvasGlue::drawLines},
     {"native_drawLine","(JFFFFJ)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
     {"native_drawRect","(JFFFFJ)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
-    {"native_drawOval","(JLandroid/graphics/RectF;J)V",
-        (void*) SkCanvasGlue::drawOval},
+    {"native_drawOval","(JFFFFJ)V", (void*) SkCanvasGlue::drawOval},
     {"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle},
-    {"native_drawArc","(JLandroid/graphics/RectF;FFZJ)V",
-        (void*) SkCanvasGlue::drawArc},
+    {"native_drawArc","(JFFFFFFZJ)V", (void*) SkCanvasGlue::drawArc},
     {"native_drawRoundRect","(JFFFFFFJ)V",
         (void*) SkCanvasGlue::drawRoundRect},
     {"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath},
@@ -1131,10 +1263,10 @@
         (void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface},
     {"native_drawText","(JLjava/lang/String;IIFFIJJ)V",
         (void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface},
-    {"native_drawTextRun","(J[CIIIIFFIJJ)V",
-        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaintTypeface},
-    {"native_drawTextRun","(JLjava/lang/String;IIIIFFIJJ)V",
-        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaintTypeface},
+    {"native_drawTextRun","(J[CIIIIFFZJJ)V",
+        (void*) SkCanvasGlue::drawTextRun___CIIIIFFZPaintTypeface},
+    {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V",
+        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFZPaintTypeface},
     {"native_drawPosText","(J[CII[FJ)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(JLjava/lang/String;[FJ)V",
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 64ad223..a4337ccc 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -3,6 +3,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "GraphicsJNI.h"
+#include "AndroidPicture.h"
 
 #include "SkCanvas.h"
 #include "SkDevice.h"
@@ -345,13 +346,13 @@
     return p;
 }
 
-SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
+AndroidPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
 {
     SkASSERT(env);
     SkASSERT(picture);
     SkASSERT(env->IsInstanceOf(picture, gPicture_class));
     jlong pictureHandle = env->GetLongField(picture, gPicture_nativeInstanceID);
-    SkPicture* p = reinterpret_cast<SkPicture*>(pictureHandle);
+    AndroidPicture* p = reinterpret_cast<AndroidPicture*>(pictureHandle);
     SkASSERT(p);
     return p;
 }
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 73dd11b..2e2f920 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -14,7 +14,7 @@
 class SkBitmapRegionDecoder;
 class SkCanvas;
 class SkPaint;
-class SkPicture;
+class AndroidPicture;
 
 class GraphicsJNI {
 public:
@@ -50,7 +50,7 @@
     static SkPaint*  getNativePaint(JNIEnv*, jobject paint);
     static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
     static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
-    static SkPicture* getNativePicture(JNIEnv*, jobject picture);
+    static AndroidPicture* getNativePicture(JNIEnv*, jobject picture);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     // Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 8b11d31..d07b154 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -707,7 +707,7 @@
     }
 
     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text,
-                                    jint start, jint count, jint contextCount, jint flags,
+                                    jint start, jint count, jint contextCount, jboolean isRtl,
                                     jfloatArray advances, jint advancesIndex) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
@@ -729,14 +729,16 @@
         jfloat* advancesArray = new jfloat[count];
         jfloat totalAdvance = 0;
 
+        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
+
 #ifdef USE_MINIKIN
         Layout layout;
-        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
         layout.doLayout(text, start, count, contextCount, css);
         layout.getAdvances(advancesArray);
         totalAdvance = layout.getAdvance();
 #else
-        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
+        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, bidiFlags,
                                        advancesArray, &totalAdvance);
 #endif
 
@@ -747,28 +749,28 @@
         return totalAdvance;
     }
 
-    static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+    static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
             jlong typefaceHandle,
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
-            jint flags, jfloatArray advances, jint advancesIndex) {
+            jboolean isRtl, jfloatArray advances, jint advancesIndex) {
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         jchar* textArray = env->GetCharArrayElements(text, NULL);
         jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
-                index - contextIndex, count, contextCount, flags, advances, advancesIndex);
+                index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
-    static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+    static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
             jlong typefaceHandle,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
             jfloatArray advances, jint advancesIndex) {
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
         jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
-                start - contextStart, end - start, contextEnd - contextStart, flags,
+                start - contextStart, end - start, contextEnd - contextStart, isRtl,
                 advances, advancesIndex);
         env->ReleaseStringChars(text, textArray);
         return result;
@@ -819,21 +821,21 @@
     }
 
     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
-            jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) {
+            jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags,
+        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
                 offset, cursorOpt);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
-            jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) {
+            jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
         jint result = doTextRunCursor(env, paint, textArray, contextStart,
-                contextEnd - contextStart, flags, offset, cursorOpt);
+                contextEnd - contextStart, dir, offset, cursorOpt);
         env->ReleaseStringChars(text, textArray);
         return result;
     }
@@ -934,32 +936,62 @@
         return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
     }
 
-    static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
+    static int breakText(JNIEnv* env, const SkPaint& paint, TypefaceImpl* typeface, const jchar text[],
                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
-                         SkPaint::TextBufferDirection tbd) {
+                         SkPaint::TextBufferDirection textBufferDirection) {
+        size_t measuredCount = 0;
+        float measured = 0;
+
+#ifdef USE_MINIKIN
+        Layout layout;
+        std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
+        layout.doLayout(text, 0, count, count, css);
+        float* advances = new float[count];
+        layout.getAdvances(advances);
+        const bool forwardScan = (textBufferDirection == SkPaint::kForward_TextBufferDirection);
+        for (int i = 0; i < count; i++) {
+            // traverse in the given direction
+            int index = forwardScan ? i : (count - i - 1);
+            float width = advances[index];
+            if (measured + width > maxWidth) {
+                break;
+            }
+            // properly handle clusters when scanning backwards
+            if (forwardScan || width != 0.0f) {
+                measuredCount = i + 1;
+            }
+            measured += width;
+        }
+        delete[] advances;
+#else
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
                 text, 0, count, count, bidiFlags);
         if (value == NULL) {
             return 0;
         }
-        SkScalar     measured;
-        size_t       bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
-                maxWidth, &measured, tbd);
+        SkScalar m;
+        size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
+                maxWidth, &m, textBufferDirection);
         SkASSERT((bytes & 1) == 0);
+        measuredCount = bytes >> 1;
+        measured = SkScalarToFloat(m);
+#endif
 
         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
             jfloat* array = autoMeasured.ptr();
-            array[0] = SkScalarToFloat(measured);
+            array[0] = measured;
         }
-        return bytes >> 1;
+        return measuredCount;
     }
 
-    static jint breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
+    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
             jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
-        NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
         SkPaint::TextBufferDirection tbd;
         if (count < 0) {
             tbd = SkPaint::kBackward_TextBufferDirection;
@@ -974,28 +1006,28 @@
             return 0;
         }
 
-        SkPaint*     paint = GraphicsJNI::getNativePaint(env, jpaint);
         const jchar* text = env->GetCharArrayElements(jtext, NULL);
-        count = breakText(env, *paint, text + index, count, maxWidth,
+        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
                           bidiFlags, jmeasuredWidth, tbd);
         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
                                       JNI_ABORT);
         return count;
     }
 
-    static jint breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
+    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
                 jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
-        NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
         SkPaint::TextBufferDirection tbd = forwards ?
                                         SkPaint::kForward_TextBufferDirection :
                                         SkPaint::kBackward_TextBufferDirection;
 
-        SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         int count = env->GetStringLength(jtext);
         const jchar* text = env->GetStringChars(jtext, NULL);
-        count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
+        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
         env->ReleaseStringChars(jtext, text);
         return count;
     }
@@ -1106,14 +1138,14 @@
     {"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII},
     {"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI},
     {"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
-    {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
-    {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
+    {"native_breakText","(JJ[CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
+    {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
     {"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
     {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
-    {"native_getTextRunAdvances","(JJ[CIIIII[FI)F",
-        (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
-    {"native_getTextRunAdvances","(JJLjava/lang/String;IIIII[FI)F",
-        (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+    {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances___CIIIIZ_FI},
+    {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances__StringIIIIZ_FI},
 
 
     {"native_getTextGlyphs","(JLjava/lang/String;IIIII[C)I",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 420a17f..6ef1d2c 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -2,22 +2,22 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** 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, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This file was generated from the C++ include file: SkPath.h
 // Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, 
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
 // or one of the auxilary file specifications in device/tools/gluemaker.
 
 #include "jni.h"
@@ -92,7 +92,7 @@
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         return obj->isEmpty();
     }
- 
+
     static jboolean isRect(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect) {
         SkRect rect;
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
@@ -100,65 +100,66 @@
         GraphicsJNI::rect_to_jrectf(rect, env, jrect);
         return result;
     }
- 
+
     static void computeBounds(JNIEnv* env, jobject clazz, jlong objHandle, jobject jbounds) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         const SkRect& bounds = obj->getBounds();
         GraphicsJNI::rect_to_jrectf(bounds, env, jbounds);
     }
- 
+
     static void incReserve(JNIEnv* env, jobject clazz, jlong objHandle, jint extraPtCount) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->incReserve(extraPtCount);
     }
- 
+
     static void moveTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->moveTo(x, y);
     }
- 
+
     static void rMoveTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rMoveTo(dx, dy);
     }
- 
+
     static void lineTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->lineTo(x, y);
     }
- 
+
     static void rLineTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rLineTo(dx, dy);
     }
- 
+
     static void quadTo__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->quadTo(x1, y1, x2, y2);
     }
- 
+
     static void rQuadTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rQuadTo(dx1, dy1, dx2, dy2);
     }
- 
+
     static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->cubicTo(x1, y1, x2, y2, x3, y3);
     }
- 
+
     static void rCubicTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->rCubicTo(x1, y1, x2, y2, x3, y3);
     }
- 
-    static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) {
+
+    static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+            jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
+            jboolean forceMoveTo) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        SkRect oval_;
-        GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
-        obj->arcTo(oval_, startAngle, sweepAngle, forceMoveTo);
+        SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+        obj->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
     }
- 
+
     static void close(JNIEnv* env, jobject clazz, jlong objHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->close();
@@ -185,28 +186,26 @@
         obj->addCircle(x, y, radius, dir);
     }
 
-    static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) {
-        SkRect oval_;
+    static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+            jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle) {
+        SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
-        obj->addArc(oval_, startAngle, sweepAngle);
+        obj->addArc(oval, startAngle, sweepAngle);
     }
 
-    static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect,
-            jfloat rx, jfloat ry, jint dirHandle) {
-        SkRect rect;
+    static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+            jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) {
+        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
-        GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
         obj->addRoundRect(rect, rx, ry, dir);
     }
-    
-    static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jobject jrect,
-            jfloatArray array, jint dirHandle) {
-        SkRect rect;
+
+    static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jfloat left, jfloat top,
+            jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
+        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
-        GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
         AutoJavaFloatArray  afa(env, array, 8);
 #ifdef SK_SCALAR_IS_FLOAT
         const float* src = afa.ptr();
@@ -215,32 +214,32 @@
 #endif
         obj->addRoundRect(rect, src, dir);
     }
-    
+
     static void addPath__PathFF(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         obj->addPath(*src, dx, dy);
     }
- 
+
     static void addPath__Path(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         obj->addPath(*src);
     }
- 
+
     static void addPath__PathMatrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong matrixHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         obj->addPath(*src, *matrix);
     }
- 
+
     static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
         obj->offset(dx, dy, dst);
     }
- 
+
     static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->offset(dx, dy);
@@ -250,14 +249,14 @@
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         obj->setLastPt(dx, dy);
     }
- 
+
     static void transform__MatrixPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle, jlong dstHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
         obj->transform(*matrix, dst);
     }
- 
+
     static void transform__Matrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
@@ -487,14 +486,14 @@
     {"native_rQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo},
     {"native_cubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
     {"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
-    {"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo},
+    {"native_arcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo},
     {"native_close","(J)V", (void*) SkPathGlue::close},
     {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
     {"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
     {"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
-    {"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc},
-    {"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY},
-    {"native_addRoundRect","(JLandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8},
+    {"native_addArc","(JFFFFFF)V", (void*) SkPathGlue::addArc},
+    {"native_addRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY},
+    {"native_addRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8},
     {"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
     {"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
     {"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index a8a3dae..0683f73 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -17,9 +17,9 @@
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
+#include "AndroidPicture.h"
 
 #include "SkCanvas.h"
-#include "SkPicture.h"
 #include "SkStream.h"
 #include "SkTemplates.h"
 #include "CreateJavaOutputStreamAdaptor.h"
@@ -29,45 +29,41 @@
 class SkPictureGlue {
 public:
     static jlong newPicture(JNIEnv* env, jobject, jlong srcHandle) {
-        const SkPicture* src = reinterpret_cast<SkPicture*>(srcHandle);
-        if (src) {
-            return reinterpret_cast<jlong>(new SkPicture(*src));
-        } else {
-            return reinterpret_cast<jlong>(new SkPicture);
-        }
+        const AndroidPicture* src = reinterpret_cast<AndroidPicture*>(srcHandle);
+        return reinterpret_cast<jlong>(new AndroidPicture(src));
     }
 
     static jlong deserialize(JNIEnv* env, jobject, jobject jstream,
                              jbyteArray jstorage) {
-        SkPicture* picture = NULL;
+        AndroidPicture* picture = NULL;
         SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
         if (strm) {
-            picture = SkPicture::CreateFromStream(strm);
+            picture = AndroidPicture::CreateFromStream(strm);
             delete strm;
         }
         return reinterpret_cast<jlong>(picture);
     }
 
     static void killPicture(JNIEnv* env, jobject, jlong pictureHandle) {
-        SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+        AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
         SkASSERT(picture);
-        picture->unref();
+        delete picture;
     }
 
     static void draw(JNIEnv* env, jobject, jlong canvasHandle,
                             jlong pictureHandle) {
         SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle);
-        SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+        AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
         SkASSERT(canvas);
         SkASSERT(picture);
         picture->draw(canvas);
     }
 
     static jboolean serialize(JNIEnv* env, jobject, jlong pictureHandle,
-                          jobject jstream, jbyteArray jstorage) {
-        SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+                              jobject jstream, jbyteArray jstorage) {
+        AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
         SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
-        
+
         if (NULL != strm) {
             picture->serialize(strm);
             delete strm;
@@ -78,19 +74,21 @@
 
     static jint getWidth(JNIEnv* env, jobject jpic) {
         NPE_CHECK_RETURN_ZERO(env, jpic);
-        int width = GraphicsJNI::getNativePicture(env, jpic)->width();
+        AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+        int width = pict->width();
         return static_cast<jint>(width);
     }
 
     static jint getHeight(JNIEnv* env, jobject jpic) {
         NPE_CHECK_RETURN_ZERO(env, jpic);
-        int height = GraphicsJNI::getNativePicture(env, jpic)->height();
+        AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+        int height = pict->height();
         return static_cast<jint>(height);
     }
 
     static jlong beginRecording(JNIEnv* env, jobject, jlong pictHandle,
-                                    jint w, jint h) {
-        SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+                                jint w, jint h) {
+        AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
         // beginRecording does not ref its return value, it just returns it.
         SkCanvas* canvas = pict->beginRecording(w, h);
         // the java side will wrap this guy in a Canvas.java, which will call
@@ -101,7 +99,7 @@
     }
 
     static void endRecording(JNIEnv* env, jobject, jlong pictHandle) {
-        SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+        AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
         pict->endRecording();
     }
 };
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index d54aaa8..3812c27 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -24,6 +24,7 @@
 #include "SkCanvas.h"
 #include "SkDocument.h"
 #include "SkPicture.h"
+#include "SkPictureRecorder.h"
 #include "SkStream.h"
 #include "SkRect.h"
 
@@ -32,15 +33,22 @@
 struct PageRecord {
 
     PageRecord(int width, int height, const SkRect& contentRect)
-            : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
+            : mPictureRecorder(new SkPictureRecorder())
+            , mPicture(NULL)
+            , mWidth(width)
+            , mHeight(height) {
         mContentRect = contentRect;
     }
 
     ~PageRecord() {
-        mPicture->unref();
+        delete mPictureRecorder;
+        if (NULL != mPicture) {
+            mPicture->unref();
+        }
     }
 
-    SkPicture* const mPicture;
+    SkPictureRecorder* mPictureRecorder;
+    SkPicture* mPicture;
     const int mWidth;
     const int mHeight;
     SkRect mContentRect;
@@ -62,8 +70,8 @@
         mPages.push_back(page);
         mCurrentPage = page;
 
-        SkCanvas* canvas = page->mPicture->beginRecording(
-                contentRect.width(), contentRect.height(), 0);
+        SkCanvas* canvas = page->mPictureRecorder->beginRecording(
+                contentRect.width(), contentRect.height(), NULL, 0);
 
         // We pass this canvas to Java where it is used to construct
         // a Java Canvas object which dereferences the pointer when it
@@ -75,7 +83,11 @@
 
     void finishPage() {
         assert(mCurrentPage != NULL);
-        mCurrentPage->mPicture->endRecording();
+        assert(mCurrentPage->mPictureRecorder != NULL);
+        assert(mCurrentPage->mPicture == NULL);
+        mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
+        delete mCurrentPage->mPictureRecorder;
+        mCurrentPage->mPictureRecorder = NULL;
         mCurrentPage = NULL;
     }
 
@@ -89,7 +101,7 @@
 
             canvas->clipRect(page->mContentRect);
             canvas->translate(page->mContentRect.left(), page->mContentRect.top());
-            canvas->drawPicture(*page->mPicture);
+            canvas->drawPicture(page->mPicture);
 
             document->endPage();
         }
@@ -97,11 +109,10 @@
     }
 
     void close() {
+        assert(NULL == mCurrentPage);
         for (unsigned i = 0; i < mPages.size(); i++) {
             delete mPages[i];
         }
-        delete mCurrentPage;
-        mCurrentPage = NULL;
     }
 
 private:
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index ddcc396..c588942 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -52,7 +52,7 @@
     jfieldID    stringType;
     jfieldID    requiredPermission;
     jfieldID    maxDelay;
-    jfieldID    isWakeUpSensor;
+    jfieldID    flags;
 } gSensorOffsets;
 
 
@@ -81,7 +81,7 @@
     sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
                                                         "Ljava/lang/String;");
     sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
-    sensorOffsets.isWakeUpSensor = _env->GetFieldID(sensorClass, "mWakeUpSensor",  "Z");
+    sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
 }
 
 static jint
@@ -117,7 +117,7 @@
     env->SetObjectField(sensor, sensorOffsets.requiredPermission,
                         requiredPermission);
     env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
-    env->SetBooleanField(sensor, sensorOffsets.isWakeUpSensor, list->isWakeUpSensor());
+    env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
     next++;
     return size_t(next) < count ? next : 0;
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index bf47dd3..ee4c619 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -244,6 +244,12 @@
 }
 
 static jint
+android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
+{
+    return AudioSystem::newAudioSessionId();
+}
+
+static jint
 android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
 {
     const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
@@ -1295,6 +1301,7 @@
     {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
     {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
+    {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
     {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index f8a1fd9..ad36843c 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -20,30 +20,10 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
 #include <utils/Log.h>
 
-namespace android {
-
-static struct {
-    jclass clazz;
-    jmethodID notify;
-} gFingerprintManagerClassInfo;
-
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
-    return -1; // TODO
-}
-
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
-    return -1; // TODO
-}
-
-// ----------------------------------------------------------------------------
-
-static const JNINativeMethod g_methods[] = {
-    { "nativeEnroll", "(I)I", (void*)nativeEnroll },
-    { "nativeRemove", "(I)I", (void*)nativeRemove },
-};
-
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
         LOG_FATAL_IF(! var, "Unable to find class " className); \
@@ -61,13 +41,174 @@
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
 
-int register_android_server_FingerprintManager(JNIEnv* env) {
-    FIND_CLASS(gFingerprintManagerClassInfo.clazz,
-            "android/service/fingerprint/FingerprintManager");
-    GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
-            "notify", "(III)V");
-    return AndroidRuntime::registerNativeMethods(
-        env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+namespace android {
+
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
+
+static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
+static struct {
+    jclass clazz;
+    jmethodID notify;
+    jobject callbackObject;
+} gFingerprintServiceClassInfo;
+
+static struct {
+    fingerprint_module_t const* module;
+    fingerprint_device_t *device;
+} gContext;
+
+// TODO: remove after driver update to use new HAL
+fingerprint_msg_type_t hackTilFpDriverUpdate(fingerprint_msg_type_t t) {
+    switch(static_cast<int>(t)) {
+        case 1: return FINGERPRINT_PROCESSED;
+        case 2: return FINGERPRINT_TEMPLATE_ENROLLING;
+        default: return t;
+    }
+}
+
+// Called by the HAL to notify us of fingerprint events
+static void hal_notify_callback(fingerprint_msg_t msg) {
+    uint32_t arg1 = 0;
+    uint32_t arg2 = 0;
+    uint32_t arg3 = 0; // TODO
+    msg.type = hackTilFpDriverUpdate(msg.type);
+    switch (msg.type) {
+        case FINGERPRINT_ERROR:
+            arg1 = msg.data.error;
+            break;
+        case FINGERPRINT_ACQUIRED:
+            arg1 = msg.data.acquired.acquired_info;
+            break;
+        case FINGERPRINT_PROCESSED:
+            arg1 = msg.data.processed.id;
+            break;
+        case FINGERPRINT_TEMPLATE_ENROLLING:
+            arg1 = msg.data.enroll.id;
+            arg2 = msg.data.enroll.samples_remaining;
+            arg3 = msg.data.enroll.data_collected_bmp;
+            break;
+        case FINGERPRINT_TEMPLATE_REMOVED:
+            arg1 = msg.data.removed.id;
+            break;
+        default:
+            ALOGE("fingerprint: invalid msg: %d", msg.type);
+            return;
+    }
+    //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
+
+	// TODO: fix gross hack to attach JNI to calling thread
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+        JavaVM* vm = AndroidRuntime::getJavaVM();
+        int result = vm->AttachCurrentThread(&env, (void*) &args);
+        if (result != JNI_OK) {
+            ALOGE("Can't call JNI method: attach failed: %#x", result);
+            return;
+        }
+    }
+    env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
+            gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
+}
+
+static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n");
+    FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+    GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz,
+           "notify", "(III)V");
+    gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj);
+}
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
+    int ret = gContext.device->enroll(gContext.device, timeout);
+    return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n");
+    int ret = gContext.device->enroll_cancel(gContext.device);
+    return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+    int ret = gContext.device->remove(gContext.device, fingerprintId);
+    return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
+    int err;
+    const hw_module_t *hw_module = NULL;
+    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
+        ALOGE("Can't open fingerprint HW Module, error: %d", err);
+        return 0;
+    }
+    if (NULL == hw_module) {
+        ALOGE("No valid fingerprint module");
+        return 0;
+    }
+
+    gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module);
+
+    if (gContext.module->common.methods->open == NULL) {
+        ALOGE("No valid open method");
+        return 0;
+    }
+
+    hw_device_t *device = NULL;
+
+    if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) {
+        ALOGE("Can't open fingerprint methods, error: %d", err);
+        return 0;
+    }
+
+    if (kVersion != device->version) {
+        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+        // return 0; // FIXME
+    }
+
+    gContext.device = reinterpret_cast<fingerprint_device_t*>(device);
+    err = gContext.device->set_notify(gContext.device, hal_notify_callback);
+    if (err < 0) {
+        ALOGE("Failed in call to set_notify(), err=%d", err);
+        return 0;
+    }
+
+    // Sanity check - remove
+    if (gContext.device->notify != hal_notify_callback) {
+        ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
+    }
+
+    ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
+    return reinterpret_cast<jlong>(gContext.device);
+}
+
+static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
+    return -ENOSYS; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+// TODO: clean up void methods
+static const JNINativeMethod g_methods[] = {
+    { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+    { "nativeEnrollCancel", "()I", (void*)nativeEnroll },
+    { "nativeRemove", "(I)I", (void*)nativeRemove },
+    { "nativeOpenHal", "()I", (void*)nativeOpenHal },
+    { "nativeCloseHal", "()I", (void*)nativeCloseHal },
+    { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
+};
+
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
+    FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+    GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify",
+            "(III)V");
+    int result = AndroidRuntime::registerNativeMethods(
+        env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
+    ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
+    return result;
 }
 
 } // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 9fa5ec9..4a6e117 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -641,16 +641,16 @@
 #endif
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
-        jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+        jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 #ifdef USE_MINIKIN
     Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
     layout.doLayout(text, 0, count, count, css);
     x += xOffsetForTextAlign(paint, layout.getAdvance());
     renderTextLayout(renderer, &layout, x, y, paint);
 #else
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, flags);
+            text, 0, count, count, bidiFlags);
     if (value == NULL) {
         return;
     }
@@ -670,9 +670,9 @@
 }
 
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, flags);
+            text, 0, count, count, bidiFlags);
     if (value == NULL) {
         return;
     }
@@ -685,16 +685,16 @@
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
-        int flags, SkPaint* paint, TypefaceImpl* typeface) {
+        int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 #ifdef USE_MINIKIN
     Layout layout;
-    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
     layout.doLayout(text, start, count, contextCount, css);
     x += xOffsetForTextAlign(paint, layout.getAdvance());
     renderTextLayout(renderer, &layout, x, y, paint);
 #else
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, start, count, contextCount, flags);
+            text, start, count, contextCount, bidiFlags);
     if (value == NULL) {
         return;
     }
@@ -715,71 +715,72 @@
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jcharArray text, jint index, jint count,
-        jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
+        jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
 
-    renderText(renderer, textArray + index, count, x, y, flags, paint, typeface);
+    renderText(renderer, textArray + index, count, x, y, bidiFlags, paint, typeface);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jstring text, jint start, jint end,
-        jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
+        jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
 
-    renderText(renderer, textArray + start, end - start, x, y, flags, paint, typeface);
+    renderText(renderer, textArray + start, end - start, x, y, bidiFlags, paint, typeface);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jcharArray text, jint index, jint count,
-        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) {
+        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
 
     renderTextOnPath(renderer, textArray + index, count, path,
-            hOffset, vOffset, flags, paint);
+            hOffset, vOffset, bidiFlags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jstring text, jint start, jint end,
-        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) {
+        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
 
     renderTextOnPath(renderer, textArray + start, end - start, path,
-            hOffset, vOffset, flags, paint);
+            hOffset, vOffset, bidiFlags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jcharArray text, jint index, jint count,
-        jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
+        jint contextIndex, jint contextCount, jfloat x, jfloat y, jboolean isRtl,
         jlong paintPtr, jlong typefacePtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
 
+    int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
     renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
-            count, contextCount, x, y, dirFlags, paint, typeface);
+            count, contextCount, x, y, bidiFlags, paint, typeface);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
  }
 
 static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jstring text, jint start, jint end,
-        jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
+        jint contextStart, int contextEnd, jfloat x, jfloat y, jboolean isRtl,
         jlong paintPtr, jlong typefacePtr) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
@@ -788,15 +789,16 @@
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
 
+    int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
     renderTextRun(renderer, textArray + contextStart, start - contextStart,
-            count, contextCount, x, y, dirFlags, paint, typeface);
+            count, contextCount, x, y, bidiFlags, paint, typeface);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
-        const jfloat* positions, jint dirFlags, SkPaint* paint) {
+        const jfloat* positions, jint bidiFlags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count, dirFlags);
+            text, 0, count, count, bidiFlags);
     if (value == NULL) {
         return;
     }
@@ -988,8 +990,8 @@
     { "nDrawTextOnPath",    "(JLjava/lang/String;IIJFFIJ)V",
             (void*) android_view_GLES20Canvas_drawTextOnPath },
 
-    { "nDrawTextRun",       "(J[CIIIIFFIJJ)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
-    { "nDrawTextRun",       "(JLjava/lang/String;IIIIFFIJJ)V",
+    { "nDrawTextRun",       "(J[CIIIIFFZJJ)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
+    { "nDrawTextRun",       "(JLjava/lang/String;IIIIFFZJJ)V",
             (void*) android_view_GLES20Canvas_drawTextRun },
 
     { "nDrawPosText",       "(J[CII[FJ)V",     (void*) android_view_GLES20Canvas_drawPosTextArray },
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 64b077b..ace17ec 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -87,14 +87,6 @@
     layer->updateTexImage();
 }
 
-static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
-        jlong layerUpdaterPtr, jlong displayListPtr,
-        jint left, jint top, jint right, jint bottom) {
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
-    layer->setDisplayList(displayList, left, top, right, bottom);
-}
-
 static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -126,7 +118,6 @@
     { "nSetSurfaceTexture",      "(JLandroid/graphics/SurfaceTexture;Z)V",
             (void*) android_view_HardwareLayer_setSurfaceTexture },
     { "nUpdateSurfaceTexture",   "(J)V",       (void*) android_view_HardwareLayer_updateSurfaceTexture },
-    { "nUpdateRenderLayer",      "(JJIIII)V",  (void*) android_view_HardwareLayer_updateRenderLayer },
 
     { "nGetLayer",               "(J)J",       (void*) android_view_HardwareLayer_getLayer },
     { "nGetTexName",             "(J)I",       (void*) android_view_HardwareLayer_getTexName },
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index e5f79f2..3ffde2d 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -87,9 +87,16 @@
 // RenderProperties - setters
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_RenderNode_setCaching(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jboolean caching) {
-    return SET_AND_DIRTY(setCaching, caching, RenderNode::GENERIC);
+static jboolean android_view_RenderNode_setLayerType(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr, jint jlayerType) {
+    LayerType layerType = static_cast<LayerType>(jlayerType);
+    return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
+}
+
+static jboolean android_view_RenderNode_setLayerPaint(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr, jlong paintPtr) {
+    SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+    return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
 }
 
 static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -275,13 +282,6 @@
     return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
 }
 
-static void android_view_RenderNode_setScrollPosition(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr, jint scrollX, jint scrollY) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    SET_AND_DIRTY(setScrollX, scrollX, RenderNode::GENERIC);
-    SET_AND_DIRTY(setScrollY, scrollY, RenderNode::GENERIC);
-}
-
 // ----------------------------------------------------------------------------
 // RenderProperties - getters
 // ----------------------------------------------------------------------------
@@ -482,7 +482,8 @@
     { "nOutput",               "(J)V",  (void*) android_view_RenderNode_output },
     { "nGetDebugSize",         "(J)I",  (void*) android_view_RenderNode_getDebugSize },
 
-    { "nSetCaching",           "(JZ)Z",  (void*) android_view_RenderNode_setCaching },
+    { "nSetLayerType",         "(JI)Z",  (void*) android_view_RenderNode_setLayerType },
+    { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
     { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
     { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
     { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
@@ -517,7 +518,6 @@
     { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
     { "nOffsetLeftAndRight",   "(JF)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
     { "nOffsetTopAndBottom",   "(JF)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
-    { "nSetScrollPosition",    "(JII)V", (void*) android_view_RenderNode_setScrollPosition },
 
     { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
     { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 11f87cc..3d14aaf 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -95,6 +95,7 @@
                 env->GetLongField(surfaceObj, gSurfaceClassInfo.mNativeObject));
         env->MonitorExit(lock);
     }
+    env->DeleteLocalRef(lock);
     return sur;
 }
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8e6c4a0..c0d5221 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -412,20 +412,12 @@
     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
 }
 
-static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
 
-    ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
-    SurfaceComposerClient::blankDisplay(token);
-}
-
-static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-
-    ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
-    SurfaceComposerClient::unblankDisplay(token);
+    ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
+    SurfaceComposerClient::setDisplayPowerMode(token, mode);
 }
 
 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
@@ -628,10 +620,6 @@
             (void*)nativeGetActiveConfig },
     {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
             (void*)nativeSetActiveConfig },
-    {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
-            (void*)nativeBlankDisplay },
-    {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
-            (void*)nativeUnblankDisplay },
     {"nativeClearContentFrameStats", "(J)Z",
             (void*)nativeClearContentFrameStats },
     {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
@@ -640,6 +628,8 @@
             (void*)nativeClearAnimationFrameStats },
     {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
             (void*)nativeGetAnimationFrameStats },
+    {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
+            (void*)nativeSetDisplayPowerMode },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index e55e4ea..226b764 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -327,6 +327,7 @@
 
             // Exception: If we find the gdbserver binary, return it.
             if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+                mLastSlash = lastSlash;
                 break;
             }
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index c58bf04..0cdddba 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -14,46 +14,40 @@
  * limitations under the License.
  */
 
-#include "android_runtime/AndroidRuntime.h"
+#define LOG_TAG "Zygote"
 
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
 #include <sys/mount.h>
 #include <linux/fs.h>
 
 #include <grp.h>
+#include <fcntl.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdlib.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
 #include <unistd.h>
-#include <fcntl.h>
+#include <sys/capability.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
 
-#include "cutils/fs.h"
-#include "cutils/multiuser.h"
-#include "cutils/sched_policy.h"
-#include "utils/String8.h"
+
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <cutils/sched_policy.h>
+#include <utils/String8.h>
+#include <selinux/android.h>
+
+#include "android_runtime/AndroidRuntime.h"
 #include "JNIHelp.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "ScopedUtfChars.h"
 
-#if defined(HAVE_PRCTL)
-#include <sys/prctl.h>
-#endif
-
-#include <selinux/android.h>
-
-#if defined(__linux__)
-#include <sys/personality.h>
-#include <sys/utsname.h>
-#if defined(HAVE_ANDROID_OS)
-#include <sys/capability.h>
-#endif
-#endif
-
 namespace {
 
 using android::String8;
@@ -97,11 +91,9 @@
       if (WTERMSIG(status) != SIGKILL) {
         ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
       }
-#ifdef WCOREDUMP
       if (WCOREDUMP(status)) {
         ALOGI("Process %d dumped core.", pid);
       }
-#endif /* ifdef WCOREDUMP */
     }
 
     // If the just-crashed process is the system_server, bring down zygote
@@ -199,8 +191,6 @@
   }
 }
 
-#if defined(HAVE_ANDROID_OS)
-
 // The debug malloc library needs to know whether it's the zygote or a child.
 extern "C" int gMallocLeakZygoteChild;
 
@@ -254,17 +244,6 @@
   }
 }
 
-#else
-
-static int gMallocLeakZygoteChild = 0;
-
-static void EnableKeepCapabilities(JNIEnv*) {}
-static void DropCapabilitiesBoundingSet(JNIEnv*) {}
-static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
-static void SetSchedulerPolicy(JNIEnv*) {}
-
-#endif
-
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
 static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
@@ -337,7 +316,6 @@
   return true;
 }
 
-#if defined(__linux__)
 static bool NeedsNoRandomizeWorkaround() {
 #if !defined(__arm__)
     return false;
@@ -357,7 +335,6 @@
     return (major < 3) || ((major == 3) && (minor < 4));
 #endif
 }
-#endif
 
 // Utility to close down the Zygote socket file descriptors while
 // the child is still running as root with Zygote's privileges.  Each
@@ -474,7 +451,6 @@
       RuntimeAbort(env);
     }
 
-#if defined(__linux__)
     if (NeedsNoRandomizeWorkaround()) {
         // Work around ARM kernel ASLR lossage (http://b/5817320).
         int old_personality = personality(0xffffffff);
@@ -483,58 +459,49 @@
             ALOGW("personality(%d) failed", new_personality);
         }
     }
-#endif
 
     SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
 
     SetSchedulerPolicy(env);
 
-#if defined(HAVE_ANDROID_OS)
-    {  // NOLINT(whitespace/braces)
-      const char* se_info_c_str = NULL;
-      ScopedUtfChars* se_info = NULL;
-      if (java_se_info != NULL) {
-          se_info = new ScopedUtfChars(env, java_se_info);
-          se_info_c_str = se_info->c_str();
-          if (se_info_c_str == NULL) {
-            ALOGE("se_info_c_str == NULL");
-            RuntimeAbort(env);
-          }
-      }
-      const char* se_name_c_str = NULL;
-      ScopedUtfChars* se_name = NULL;
-      if (java_se_name != NULL) {
-          se_name = new ScopedUtfChars(env, java_se_name);
-          se_name_c_str = se_name->c_str();
-          if (se_name_c_str == NULL) {
-            ALOGE("se_name_c_str == NULL");
-            RuntimeAbort(env);
-          }
-      }
-      rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
-      if (rc == -1) {
-        ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
-              is_system_server, se_info_c_str, se_name_c_str);
-        RuntimeAbort(env);
-      }
-
-      // Make it easier to debug audit logs by setting the main thread's name to the
-      // nice name rather than "app_process".
-      if (se_info_c_str == NULL && is_system_server) {
-        se_name_c_str = "system_server";
-      }
-      if (se_info_c_str != NULL) {
-        SetThreadName(se_name_c_str);
-      }
-
-      delete se_info;
-      delete se_name;
+    const char* se_info_c_str = NULL;
+    ScopedUtfChars* se_info = NULL;
+    if (java_se_info != NULL) {
+        se_info = new ScopedUtfChars(env, java_se_info);
+        se_info_c_str = se_info->c_str();
+        if (se_info_c_str == NULL) {
+          ALOGE("se_info_c_str == NULL");
+          RuntimeAbort(env);
+        }
     }
-#else
-    UNUSED(is_system_server);
-    UNUSED(java_se_info);
-    UNUSED(java_se_name);
-#endif
+    const char* se_name_c_str = NULL;
+    ScopedUtfChars* se_name = NULL;
+    if (java_se_name != NULL) {
+        se_name = new ScopedUtfChars(env, java_se_name);
+        se_name_c_str = se_name->c_str();
+        if (se_name_c_str == NULL) {
+          ALOGE("se_name_c_str == NULL");
+          RuntimeAbort(env);
+        }
+    }
+    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+    if (rc == -1) {
+      ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+            is_system_server, se_info_c_str, se_name_c_str);
+      RuntimeAbort(env);
+    }
+
+    // Make it easier to debug audit logs by setting the main thread's name to the
+    // nice name rather than "app_process".
+    if (se_info_c_str == NULL && is_system_server) {
+      se_name_c_str = "system_server";
+    }
+    if (se_info_c_str != NULL) {
+      SetThreadName(se_name_c_str);
+    }
+
+    delete se_info;
+    delete se_name;
 
     UnsetSigChldHandler();
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8fc5b7b..c08c5e2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -123,10 +123,30 @@
     <protected-broadcast
         android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
     <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+    <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+    <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+    <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+    <protected-broadcast
+        android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+    <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
     <protected-broadcast
+        android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast
+        android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+    <protected-broadcast
+        android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+   <protected-broadcast
+        android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast
         android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
@@ -1770,11 +1790,11 @@
 
     <!-- Allows the system to bind to an application's task services
          @hide -->
-    <permission android:name="android.permission.BIND_TASK_SERVICE"
+    <permission android:name="android.permission.BIND_JOB_SERVICE"
         android:protectionLevel="signature"
-        android:label="@string/permlab_bindTaskService"
-        android:description="@string/permdesc_bindTaskService" />
-    <uses-permission android:name="android.permission.BIND_TASK_SERVICE"/>
+        android:label="@string/permlab_bindJobService"
+        android:description="@string/permdesc_bindJobService" />
+    <uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
 
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
@@ -2071,6 +2091,14 @@
         android:description="@string/permdesc_bindVoiceInteraction"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by hotword enrollment application,
+         to ensure that only the system can interact with it.
+         @hide <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
+        android:label="@string/permlab_manageVoiceKeyphrases"
+        android:description="@string/permdesc_manageVoiceKeyphrases"
+        android:protectionLevel="signature|system" />
+
     <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
          to ensure that only the system can bind to it.
          @hide -->
@@ -2635,6 +2663,13 @@
                 android:label="@string/permlab_provide_trust_agent"
                 android:description="@string/permdesc_provide_trust_agent" />
 
+    <!-- Allows an application to launch the trust agent settings activity.
+        @hide -->
+    <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
+        android:protectionLevel="signatureOrSystem"
+        android:label="@string/permlab_launch_trust_agent_settings"
+        android:description="@string/permdesc_launch_trust_agent_settings" />
+
     <!-- Must be required by an {@link
          android.service.trust.TrustAgentService},
          to ensure that only the system can bind to it. -->
@@ -2699,7 +2734,8 @@
                 android:theme="@style/Theme.Holo.Dialog.Alert"
                 android:finishOnCloseSystemDialogs="true"
                 android:excludeFromRecents="true"
-                android:multiprocess="true">
+                android:multiprocess="true"
+                android:documentLaunchMode="never">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -2888,8 +2924,14 @@
         </service>
 
         <service android:name="com.android.server.MountServiceIdler"
-                 android:exported="false"
-                 android:permission="android.permission.BIND_TASK_SERVICE" >
+                 android:exported="true"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
+        <service
+            android:name="com.android.server.pm.BackgroundDexOptService"
+            android:exported="true"
+            android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
     </application>
diff --git a/core/res/assets/images/android-logo-mask.png b/core/res/assets/images/android-logo-mask.png
index 3078b28..ad40645 100644
--- a/core/res/assets/images/android-logo-mask.png
+++ b/core/res/assets/images/android-logo-mask.png
Binary files differ
diff --git a/core/res/assets/images/android-logo-shine.png b/core/res/assets/images/android-logo-shine.png
index add6796..cb65f22 100644
--- a/core/res/assets/images/android-logo-shine.png
+++ b/core/res/assets/images/android-logo-shine.png
Binary files differ
diff --git a/core/res/res/anim-land/task_close_enter.xml b/core/res/res/anim-land/task_close_enter.xml
deleted file mode 100644
index facc42b..0000000
--- a/core/res/res/anim-land/task_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="300"
-            android:duration="400"/>
-
-    <translate android:fromXDelta="-120%" android:toXDelta="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="300"
-            android:duration="400" />
-
-    <scale android:fromXScale=".5" android:toXScale="1.0"
-            android:fromYScale=".5" android:toYScale="1.0"
-            android:pivotY="50%p" android:pivotX="0%p"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="300"
-            android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_close_exit.xml b/core/res/res/anim-land/task_close_exit.xml
deleted file mode 100644
index e104c33..0000000
--- a/core/res/res/anim-land/task_close_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="300"/>
-
-    <translate android:fromXDelta="0" android:toXDelta="120%"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_cubic"
-            android:duration="300"/>
-
-    <scale android:fromXScale="1.0" android:toXScale="0.5"
-            android:fromYScale="1.0" android:toYScale="0.5"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotY="50%p" android:pivotX="100%p"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="300" />
-
-    <!-- This is needed to keep the animation running while task_open_enter completes -->
-    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:duration="700" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_enter.xml b/core/res/res/anim-land/task_open_enter.xml
deleted file mode 100644
index dc7c7a9..0000000
--- a/core/res/res/anim-land/task_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="300"
-            android:duration="400"/>
-
-    <translate android:fromXDelta="120%" android:toXDelta="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="300"
-            android:duration="400" />
-
-    <scale android:fromXScale=".5" android:toXScale="1.0"
-            android:fromYScale=".5" android:toYScale="1.0"
-            android:pivotY="50%p" android:pivotX="100%p"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="300"
-            android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_exit.xml b/core/res/res/anim-land/task_open_exit.xml
deleted file mode 100644
index 701afa6..0000000
--- a/core/res/res/anim-land/task_open_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="300"/>
-
-    <translate android:fromXDelta="0" android:toXDelta="-120%"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_cubic"
-            android:duration="300"/>
-
-    <scale android:fromXScale="1.0" android:toXScale="0.5"
-            android:fromYScale="1.0" android:toYScale="0.5"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotY="50%p" android:pivotX="0%p"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="300" />
-
-    <!-- This is needed to keep the animation running while task_open_enter completes -->
-    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:duration="700" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_enter.xml b/core/res/res/anim-sw720dp/task_close_enter.xml
deleted file mode 100644
index e25978b..0000000
--- a/core/res/res/anim-sw720dp/task_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="500"
-            android:duration="400"/>
-
-    <translate android:fromYDelta="-50%" android:toYDelta="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="500"
-            android:duration="400" />
-
-    <scale android:fromXScale=".8" android:toXScale="1.0"
-            android:fromYScale=".8" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="0%p"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="500"
-            android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_exit.xml b/core/res/res/anim-sw720dp/task_close_exit.xml
deleted file mode 100644
index 2d7e2a6..0000000
--- a/core/res/res/anim-sw720dp/task_close_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350"/>
-
-    <translate android:fromYDelta="0" android:toYDelta="50%"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_cubic"
-            android:duration="350"/>
-
-    <scale android:fromXScale="1.0" android:toXScale="0.8"
-            android:fromYScale="1.0" android:toYScale="0.8"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="100%p"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350" />
-
-    <!-- This is needed to keep the animation running while task_close_enter completes -->
-    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:duration="900" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_enter.xml b/core/res/res/anim-sw720dp/task_open_enter.xml
deleted file mode 100644
index d583b6e..0000000
--- a/core/res/res/anim-sw720dp/task_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="500"
-            android:duration="400"/>
-
-    <translate android:fromYDelta="50%" android:toYDelta="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:startOffset="500"
-            android:duration="400" />
-
-    <scale android:fromXScale=".8" android:toXScale="1.0"
-            android:fromYScale=".8" android:toYScale="1.0"
-            android:pivotX="50%p" android:pivotY="100%p"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/decelerate_quad"
-            android:startOffset="500"
-            android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_exit.xml b/core/res/res/anim-sw720dp/task_open_exit.xml
deleted file mode 100644
index dd25a0c..0000000
--- a/core/res/res/anim-sw720dp/task_open_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350"/>
-
-    <translate android:fromYDelta="0" android:toYDelta="-50%"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@interpolator/accelerate_cubic"
-            android:duration="350"/>
-
-    <scale android:fromXScale="1.0" android:toXScale="0.8"
-            android:fromYScale="1.0" android:toYScale="0.8"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:pivotX="50%p" android:pivotY="0%p"
-            android:interpolator="@interpolator/accelerate_quad"
-            android:duration="350" />
-
-    <!-- This is needed to keep the animation running while task_open_enter completes -->
-    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
-            android:duration="900" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index 17acfc5..c5c0e97 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index 17acfc5..c5c0e97 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
index 9b8ca22..3b31225 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
index 9b8ca22..3b31225 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
index bc20f6c..b65009e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
index bc20f6c..b65009e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
index 571819b..a2dfcae 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
index 571819b..c3fda0e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 1f83b5a..bae60a7 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 1f83b5a..bae60a7 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
index 733cf45..a9653b0 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
index 733cf45..a9653b0 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
index 2265de4..394cb5e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
index 2265de4..394cb5e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
index f3ada58..aa23c6e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
index f3ada58..028b3b8 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..0c3c3b4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_blue.9.png b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..b991535
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_green.9.png b/core/res/res/drawable-hdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..c8de61d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_orange.9.png b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..10347e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_purple.9.png b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..ac4ee01
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_blue.9.png b/core/res/res/drawable-hdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..b2c5581
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_green.9.png b/core/res/res/drawable-hdpi/sim_light_green.9.png
new file mode 100755
index 0000000..4d29c81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_orange.9.png b/core/res/res/drawable-hdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..68c6c2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_purple.9.png b/core/res/res/drawable-hdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..4deb8dc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png
deleted file mode 100644
index be8a36e..0000000
--- a/core/res/res/drawable-hdpi/work_icon.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index 3fdd3bc..4e6d076 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index 3fdd3bc..4e6d076 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
index eaa02b3..ca61cb2 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
index eaa02b3..ca61cb2 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
index 28c8b94..b5999be 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
index 28c8b94..b5999be 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
index 6090cce..8392ac3 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
index 6090cce..522bafd 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 3f2e982..ebb2f8b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 3f2e982..ebb2f8b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
index 14b958b..3fa20ca 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
index 14b958b..3fa20ca 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
index 4db22d4..6cc59ed 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
index 4db22d4..6cc59ed 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
index a11e1c7..a1fcd08 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
index a11e1c7..c6c0224 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..8322ae3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_blue.9.png b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..d646a7f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_green.9.png b/core/res/res/drawable-mdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..ee4ea0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_orange.9.png b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..b394999
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_purple.9.png b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..459b5d69
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_blue.9.png b/core/res/res/drawable-mdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..396ad70
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_green.9.png b/core/res/res/drawable-mdpi/sim_light_green.9.png
new file mode 100755
index 0000000..a063174
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_orange.9.png b/core/res/res/drawable-mdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..95ea88e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_purple.9.png b/core/res/res/drawable-mdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..b1bd35f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index c08deab..1e45530 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index c08deab..1e45530 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png
index 8b1a55c..2c63c5d 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png
index 8b1a55c..2c63c5d 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png
index 77cd1fa..dd5e26e 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png
index 77cd1fa..dd5e26e 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png
index e0e3540..aa9b3c5 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png
index e0e3540..367c25a 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 324e490..df28ad0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 324e490..df28ad0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png
index e126cc6..3a27831 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png
index e126cc6..3a27831 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png
index 4c1f1b9..d68bdf4 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png
index 4c1f1b9..d68bdf4 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png
index 219d37b..da03ec9 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png
index 219d37b..482b249 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..e6c0047
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..bb9debb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable/dialog_background_shadow_material.xml b/core/res/res/drawable/dialog_background_shadow_material.xml
new file mode 100644
index 0000000..0554920
--- /dev/null
+++ b/core/res/res/drawable/dialog_background_shadow_material.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/dialog_background_mtrl_mult"
+    android:tint="?attr/colorBackground"
+    android:tintMode="multiply" />
diff --git a/core/res/res/layout/dialog_custom_title_material.xml b/core/res/res/layout/dialog_custom_title_material.xml
index 1bb93eb..550b72e 100644
--- a/core/res/res/layout/dialog_custom_title_material.xml
+++ b/core/res/res/layout/dialog_custom_title_material.xml
@@ -23,6 +23,7 @@
     android:fitsSystemWindows="true">
     <FrameLayout android:id="@android:id/title_container"
         android:layout_width="match_parent"
+        android:layout_height="?android:attr/windowTitleSize"
         android:layout_weight="0"
         android:gravity="center_vertical|start"
         style="?android:attr/windowTitleBackgroundStyle" />
diff --git a/core/res/res/layout/dialog_title_material.xml b/core/res/res/layout/dialog_title_material.xml
index b92c1e7..918c8f1 100644
--- a/core/res/res/layout/dialog_title_material.xml
+++ b/core/res/res/layout/dialog_title_material.xml
@@ -22,7 +22,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:fitsSystemWindows="true">
-    <TextView android:id="@+id/alertTitle"
+    <TextView android:id="@+id/title"
         style="?android:attr/windowTitleStyle"
         android:singleLine="true"
         android:ellipsize="end"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index bdf27c8..0564a8f 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -145,7 +145,7 @@
                 android:layout_marginStart="8dp"
                 android:layout_marginEnd="8dp"
                 android:visibility="gone"
-                style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+                style="@style/Widget.StatusBar.Material.ProgressBar"
                 />
         </LinearLayout>
         <ImageView
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index c89b9f9..f8e1986 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -38,7 +38,6 @@
             android:minHeight="@dimen/notification_large_icon_height"
             android:paddingTop="2dp"
             android:orientation="vertical"
-            android:background="@color/notification_media_info_bg"
             >
             <LinearLayout
                 android:id="@+id/line1"
@@ -147,7 +146,7 @@
                 android:layout_height="6dp"
                 android:layout_gravity="top"
                 android:visibility="gone"
-                style="@style/Widget.StatusBar.Material.ProgressBar"
+                style="@style/Widget.StatusBar.Material.ProgressBar.Media"
                 />
         </FrameLayout>
     </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 6f8c3a9..1de5add 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -99,7 +99,7 @@
                 android:layout_marginEnd="8dp"
                 android:visibility="gone"
                 android:layout_weight="0"
-                style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+                style="@style/Widget.StatusBar.Material.ProgressBar"
                 />
             <TextView android:id="@+id/big_text"
                 android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
diff --git a/core/res/res/layout/preference_material.xml b/core/res/res/layout/preference_material.xml
index a4fe73d..a9599139 100644
--- a/core/res/res/layout/preference_material.xml
+++ b/core/res/res/layout/preference_material.xml
@@ -31,7 +31,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="58dip"
-        android:gravity="left|center_vertical"
+        android:gravity="start|center_vertical"
         android:orientation="horizontal">
         <ImageView
             android:id="@+android:id/icon"
diff --git a/core/res/res/layout/preference_widget_seekbar.xml b/core/res/res/layout/preference_widget_seekbar.xml
index c427965..05daa1a 100644
--- a/core/res/res/layout/preference_widget_seekbar.xml
+++ b/core/res/res/layout/preference_widget_seekbar.xml
@@ -14,9 +14,7 @@
      limitations under the License.
 -->
 
-<!-- Layout for a Preference in a PreferenceActivity. The
-     Preference is able to place a specific widget for its particular
-     type in the "widget_frame" layout. -->
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/core/res/res/layout/preference_widget_seekbar_material.xml b/core/res/res/layout/preference_widget_seekbar_material.xml
new file mode 100644
index 0000000..f70a472
--- /dev/null
+++ b/core/res/res/layout/preference_widget_seekbar_material.xml
@@ -0,0 +1,86 @@
+<?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.
+-->
+
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:minWidth="@dimen/preference_icon_minWidth"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:minWidth="48dp"
+            />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dip"
+        android:layout_marginEnd="8dip"
+        android:layout_marginTop="6dip"
+        android:layout_marginBottom="6dip"
+        android:layout_weight="1">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="4" />
+
+        <!-- Preference should place its actual preference widget here. -->
+        <LinearLayout android:id="@+android:id/widget_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_below="@android:id/summary"
+            android:layout_alignStart="@android:id/title"
+            android:minWidth="@dimen/preference_widget_width"
+            android:gravity="center"
+            android:orientation="vertical" />
+
+        <SeekBar android:id="@+android:id/seekbar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/summary"
+            android:layout_toEndOf="@android:id/widget_frame"
+            android:layout_alignParentEnd="true" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml
new file mode 100755
index 0000000..9f8f2b3
--- /dev/null
+++ b/core/res/res/layout/subscription_item_layout.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright (C) 2014 MediaTek Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" >
+    <RelativeLayout
+        android:layout_width="48dip"
+        android:layout_height="32dip"
+        android:id="@+id/sub_color"
+        android:layout_marginEnd="6dip"
+        android:layout_centerVertical="true">
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/sub_short_number"
+            android:layout_marginBottom="2dip"
+            android:layout_marginEnd="4dip"
+            android:layout_alignParentEnd="true" 
+            android:layout_alignParentBottom="true"
+            android:textSize="12sp"
+            android:singleLine="true"
+            android:textColor="@android:color/white"
+            android:includeFontPadding="false"/>
+    </RelativeLayout>
+    <RelativeLayout
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:layout_centerVertical="true">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/sub_name"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:requiresFadingEdge="horizontal"
+            android:scrollHorizontally="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/sub_number"
+            android:layout_below="@+id/sub_name"
+            android:layout_alignStart="@+id/sub_name"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:requiresFadingEdge="horizontal"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"/>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index bd92c53..72b0909 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Persoonlike programme"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android vir Werk"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Werk"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Dienste wat jou geld kos"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Doen dinge wat jou geld kan kos."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Jou boodskappe"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n muurpapier te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"verbind met \'n steminteraksiediens"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Laat die houer toe om met die topvlak-koppelvlak van \'n steminteraksiediens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"bestuur stemsleutelfrases"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Laat die houer toe om die sleutelfrases vir aktiveerwoordbespeuring met stem te bestuur. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"koppel aan \'n afstandskerm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"laat program gedurende ledige tyd loop"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met hierdie toestemming kan die Android-stelsel die program in die agtergrond laat loop terwyl die toestel nie gebruik word nie."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"laat loop die program se geskeduleerde agtergrondwerk"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Hierdie toestemming laat die Android-stelsel toe om die program in die agtergrond te laat loop wanneer dit versoek word."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Laat \'n program toe om vir veranderinge in vertrouenstaat te luister."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Voorsien \'n vertroude agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Laat \'n program toe om \'n vertroude agent te voorsien."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Verbind met \'n vertrouensagentdiens"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Laat \'n program toe om met \'n vertrouensagentdiens te verbind."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Tree in wisselwerking met opdatering- en terugstellingstelsel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b2b93ab..da89136 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"የግል መተግበሪያዎች"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android ለስራ"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android ስራ"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"ገንዘብ የሚያስወጥዎ አገልግሎቶች"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ገንዘብ የሚያስወጡህን ነገሮች አድርግ።"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"መልዕክቶችዎ"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ከአንድ የድምጽ በይነተገናኝ ጋር ይሰሩ"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ያዢው የአንድ የድምጽ በይነግንኙነት አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ድምጽ የቁልፍ ሃረጎችን አስተዳድር"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"መያዣው የቁልፍ ሃረጎችን ለድምጽ ትኩስ ቃል ለይቶ ማወቂያ እንዲያስተዳድር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች ማስፈለግ የለበትም።"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም  ለመተግበሪያ ይፈቅዳል።"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ስራ በተፈታበት ጊዜ ላይ መተግበሪያውን አሂድ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ይህ ፍቃድ መሣሪያው ስራ ላይ ባልሆነ ጊዜ የAndroid ስርዓቱ መተግበሪያውን በጀርባ ውስጥ እንዲያሂደው ያስችለዋል።"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"መርሐግብር የተያዘለት የመተግበሪያ የጀርባ ስራ አሂድ"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"ይህ ፍቃድ የAndroid ስርዓቱ ሲጠየቅ መተግበሪያውን በጀርባ እንዲያሂደው ይፈቅድለታል።"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"መተግበሪያው በተአማኒነት ሁኔታ ውስጥ ለውጦችን እንዲያዳምጥ ይፈቅዳል።"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"የመታመን ወኪል ያቅርቡ።"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"አንድ መተግበሪያ የመታመን ወኪል እንዲያቀርብ ይፈቅድለታል።"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"የእምነት ወኪል ቅንብሮች ምናሌን አስጀምር።"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"አንድ መተግበሪያ የእምነት ወኪል ባህሪ የሚቀይር እንቅስቃሴ እንዲያስጀምር ያስችለዋል።"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ለተአማኒነት ወኪል አገልግሎት ተገዢ አድርግ"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ለመተግበሪያን የተአማኒነት ወኪል አገልግሎትን እንዲያከብር ይፈቅዳል።"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"ከዝማኔዎች እና ከመልሶ ማግኛ ስርዓቶች ጋር ይገናኙ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e5a3f39..626858f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏نظام Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"التطبيقات الشخصية"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"‏Android للعمل"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"‏عمل Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"الخدمات التي تكلفك المال"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"يمكنك تنفيذ إجراءات يمكن أن تكلفك مالاً."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"رسائلك"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"الربط بخدمة التفاعل الصوتي"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة التفاعل الصوتي. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"إدارة العبارات الأساسية الصوتية"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"للسماح للمالك بإدارة العبارات الأساسية لاكتشاف الكلمات المهمة الصوتية. لا يجب استخدامه على الإطلاق للتطبيقات العادية."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"تشغيل التطبيق أثناء وقت الخمول"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"‏يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية في حين أن الجهاز ليس قيد الاستخدام."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"تشغيل عمل الخلفية المجدول للتطبيق"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"‏يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية عند طلبه."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"للسماح للتطبيق بالتعرف على التغييرات في حالة الاعتماد."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"توفير وكيل معتمد."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"للسماح لأحد التطبيقات بتوفير وكيل معتمد."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"تشغيل قائمة إعدادات الوكيل المعتمد."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"للسماح لأحد التطبيقات بتشغيل نشاط يؤدي إلى تغيير سلوك الوكيل المعتمد."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"الالتزام بخدمة الوكيل المعتمد"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"للسماح لأحد التطبيقات بالالتزام بخدمة الوكيل المعتمد."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"التفاعل مع نظام التحديث والاسترداد"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0985844..ca71ce3 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Лични приложения"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android за работа"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Служебен под Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Услуги, които ви струват пари"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Извършват неща, които могат да ви струват пари."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Вашите съобщения"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"свързване с услуга за гласово взаимодействие"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за гласово взаимодействие. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"управление на гласовите ключови фрази"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Разрешава на притежателя да управлява ключовите фрази за функцията за откриване на произнесени активиращи думи. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"изпълняване на приложението по време на неактивност"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Това разрешение позволява на системата Android да изпълнява приложението на заден план, докато устройството не се използва."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"изпълняване на планираната за извършване на заден план работа на приложението"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Това разрешение позволява на системата Android да изпълнява приложението на заден план при заявяване."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Разрешава на приложението да следи за промени в състоянието на надеждност."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Предоставяне на trust agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Разрешава на приложението да предоставя trust agent."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Обвързване с услуга за trust agents"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Разрешава на приложението да се обвърже с услуга за trust agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействие със системата за актуализации и възстановяване"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 900aef3..e1eed49 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplicacions personals"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android per a la feina"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Lloc a Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serveis de pagament"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dur a terme activitats de pagament."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Missatges"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet que el titular vinculi a la interfície de nivell superior d\'un fons de pantalla. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"enllaçar amb una eina d\'interacció de veu"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet enllaçar amb la interfície de nivell superior d\'un servei d\'interacció de veu. No ha de ser mai necessari per a aplicacions normals."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestiona les frases clau en veu alta"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permet que l\'usuari gestioni les frases clau per detectar paraules actives que es diguin en veu alta. Mai no hauria de ser necessari per a les aplicacions habituals."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincula a una pantalla remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"executar l\'aplicació durant el temps d\'inactivitat"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Aquest permís permet que el sistema Android executi l\'aplicació en segon pla mentre el dispositiu no està en ús."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"executa les tasques programades de l\'aplicació en segon pla"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Mitjançant aquest permís, el sistema Android pot executar l\'aplicació en segon pla quan se li ho sol·liciti."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet que una aplicació escolti els canvis en l\'estat de confiança."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agent de confiança"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permet que una aplicació proporcioni un agent de confiança."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enllaçar amb el servei d\'un agent de confiança"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet que una aplicació es vinculi amb el servei d\'un agent de confiança."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interacciona amb el sistema de recuperació i amb les actualitzacions"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a004044..cf06dc1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Osobní aplikace"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android pro práci"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android pro práci"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Zpoplatněné služby"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Provádět činnosti, které vás mohou stát peníze."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše zprávy"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní tapety. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"navázání na hlasovou interakci"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby hlasové interakce. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"správa klíčových hlasových frází"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Umožňuje držiteli spravovat klíčové hlasové fráze pro detekci hlasových klíčových slov. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"připojit se ke vzdálenému displeji"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"spustit aplikaci během nečinnosti"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když zařízení není používáno."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"spustit naplánovanou práci aplikace na pozadí"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když je to požadováno."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikaci naslouchat změnám ve stavu důvěryhodnosti."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Poskytování zástupce důvěryhodnosti"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Umožňuje aplikaci poskytnout zástupce důvěryhodnosti."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vázat se na službu zástupce důvěryhodnosti"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikaci vázat se na službu zástupce důvěryhodnosti."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakce se systémem aktualizací a obnovení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 7ad7c81..0aa2a36 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Personlige apps"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android til arbejdsbrug"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjenester, der koster dig penge"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gør ting, der kan koste dig penge."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Dine beskeder"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Tillader, at indehaveren kan binde en baggrunds grænseflade på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"oprette binding til en tjeneste til stemmeinteraktion"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til stemmeinteraktion. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrer nøglesætninger til stemmeregistrering"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Tillader, at brugeren kan administrere nøglesætningerne til stemmeregistrering af kommandoord. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind til en ekstern skærm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"kør applikation, mens enheden er i dvale"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, mens enheden ikke er i brug."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"kør applikationens planlagte baggrundsarbejde"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, når det er nødvendigt."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen,  f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -521,7 +523,7 @@
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Registrering af kommandoord"</string>
     <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillader, at appen optager lyd til registrering af kommandoord. Optagelsen kan ske i baggrunden, men forhindrer ikke andre lydoptagelser (f.eks. videokamera)."</string>
     <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Lydhåndtering"</string>
-    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Tillader, at appen direkte kontrollerer lydhåndteringen og tilsidesætter beslutninger, som foretages af lydpolitikker."</string>
+    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Tillader, at appen direkte kontrollerer lydhåndteringen og tilsidesætter beslutninger, baseret på af lydpolitikker."</string>
     <string name="permlab_captureVideoOutput" msgid="2246828773589094023">"opfang et videooutput"</string>
     <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillader, at appen opfanger og omdirigerer et videooutput."</string>
     <string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"opfang et sikkert videooutput"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillader, at en applikation registrerer ændringer i trust-tilstand."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Angiv en tillidsagent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillader, at en applikation angiver en tillidsagent."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Åbn indstillingsmenuen for tillidsagenten"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Giver en applikation tilladelse til at starte en aktivitet, som ændrer adfærden for tillidsagenten."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Knytte sig til en trust agent-tjeneste"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillader, at en applikation knytter sig til en trust agent-tjeneste."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interager med opdaterings- og gendannelsessystemet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index cc1f042..d557d37 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Private Apps"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android für Geschäftliches"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android – Arbeit"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Kostenpflichtige Aktionen"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ermöglicht dem Halter, sich an die Oberfläche eines Hintergrunds auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"An einen Sprachinteraktionsdienst binden"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Sprachinteraktionsdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"Suchbegriffe für die Sprachsuche verwalten"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ermöglicht dem Inhaber die Verwaltung von Suchbegriffen für die Hotword-Erkennung bei der Sprachbedienung. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"An Remote-Display binden"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"App bei Inaktivität ausführen"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Diese Berechtigung ermöglicht es dem Android-System, die App im Hintergrund auszuführen, wenn das Gerät nicht verwendet wird."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"Geplante Aufgaben der App im Hintergrund ausführen"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Diese Berechtigung ermöglicht es dem Android-System, die App bei Bedarf im Hintergrund auszuführen."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ermöglicht einer App die Überwachungen von Änderungen des Trust-Status"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust Agent bereitstellen"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ermöglich die Bereitstellung eines Trust Agents durch eine App"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Einstellungsmenü des Trust Agents starten"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ermöglicht einer App das Starten einer Aktivität, die das Verhalten des Trust Agents ändert"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"An Trust Agent-Service anbinden"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a04635d..8205c60 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Προσωπικές εφαρμογές"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for Work"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Υπηρεσίες επί πληρωμή"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Πραγματοποίηση ενεργειών για τις οποίες ενδέχεται να χρεωθείτε."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Τα μηνύματά σας"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"σύνδεση σε παράγοντα φωνητικής αλληλεπίδρασης"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας φωνητικής αλληλεπίδρασης. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"διαχείριση φωνητικών φράσεων-κλειδιών"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Δίνει στον κάτοχο τη δυνατότητα να διαχειριστεί τις φράσεις-κλειδιά για την ανίχνευση φωνητικών λέξεων-κλειδιών. Δεν απαιτείται για τις συνήθεις εφαρμογές."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"εκτέλεση εφαρμογής κατά τη λειτουργία αδράνειας"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν δεν χρησιμοποιείται η συσκευή."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"εκτέλεση των προγραμματισμένων εργασιών της εφαρμογής στο παρασκήνιο"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν ζητηθεί."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Επιτρέπει σε μια εφαρμογή να αντιλαμβάνεται τις αλλαγές στην κατάσταση εμπιστοσύνης."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Παράσχετε έναν αξιόπιστο αντιπρόσωπο."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Επιτρέπει σε μια εφαρμογή να προσφέρει έναν αξιόπιστο αντιπρόσωπο."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Εκκίνηση μενού ρυθμίσεων αξιόπιστου αντιπροσώπου."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Επιτρέπει σε μια εφαρμογή να εκκινεί μια ενέργεια που αλλάζει τη συμπεριφορά του αξιόπιστου αντιπροσώπου."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Σύνδεση σε υπηρεσία trust agent"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Επιτρέπει σε μια εφαρμογή να συνδεθεί σε μια υπηρεσία trust agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Αλληλεπίδραση με το σύστημα ενημέρωσης και ανάκτησης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 24ae577..a0c35c8 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Personal apps"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for Work"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services that cost you money"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Do things that can cost you money."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Your messages"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind to a voice interactor"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Allows the holder to bind to the top-level interface of a voice interaction service. Should never be needed for normal apps."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"manage voice key phrases"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Allows the holder to manage the key phrases for voice hotword detection. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"run the application\'s scheduled background work"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"This permission allows the Android system to run the application in the background when requested."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Provide a trust agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Allows an application to provide a trust agent."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Lunch trust agent settings menu."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Allows an application to lunch an activity that changes the trust agent behaviour."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 24ae577..a0c35c8 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Personal apps"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for Work"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services that cost you money"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Do things that can cost you money."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Your messages"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind to a voice interactor"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Allows the holder to bind to the top-level interface of a voice interaction service. Should never be needed for normal apps."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"manage voice key phrases"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Allows the holder to manage the key phrases for voice hotword detection. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"run the application\'s scheduled background work"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"This permission allows the Android system to run the application in the background when requested."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Provide a trust agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Allows an application to provide a trust agent."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Lunch trust agent settings menu."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Allows an application to lunch an activity that changes the trust agent behaviour."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3e5538c..b6a7667 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplicaciones personales"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android para el trabajo"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Trabajo Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Permite que las aplicaciones realicen actividades con cargo."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deben utilizar este permiso."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vincular con un servicio de interacción por voz"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite vincular con la interfaz de nivel superior de un servicio de interacción por voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrar frases clave de voz"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite administrar las frases clave para detección de palabras activas de voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincular a una pantalla remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano mientras el dispositivo no está en uso."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"Ejecutar el trabajo en segundo plano programado de la aplicación"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano cuando sea necesario."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agente de confianza"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que una aplicación proporcione un agente de confianza."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Iniciar menú de configuración de agente de confianza"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Permite que una aplicación inicie una actividad que modifica el comportamiento del agente de confianza."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular con un servicio de agente de confianza"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que una aplicación se vincule con un servicio de agente de confianza."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interaccionar con el sistema de recuperación y las actualizaciones"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 18b321f..1dcbf62 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplicaciones personales"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android para el trabajo"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Trabajo Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios por los que tienes que pagar"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Hacer acciones por las que puede que tengas que pagar"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite enlazar con la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"enlazar con un servicio de interacción de voz"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite enlazar con la interfaz de nivel superior de un servicio de interacción de voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrar frases clave de voz"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite administrar las frases clave para la detección de palabras activas. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"enlazar a una pantalla remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esto permite que el sistema Android ejecute la aplicación en segundo plano mientras el dispositivo no se utiliza."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"ejecutar el trabajo en segundo plano programado de la aplicación"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Esto permite que el sistema Android ejecute la aplicación en segundo plano cuando se solicite."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agente de confianza."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que una aplicación proporcione un agente de confianza."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Abre el menú de ajustes del agente de confianza."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Permite que una aplicación inicie una actividad que cambie el comportamiento del agente de confianza."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enlazar con un servicio de agente de confianza"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite a una aplicación enlazar con un servicio de agente de confianza."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interactuar con el sistema de recuperación y las actualizaciones"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 922a9af1..60d036e 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Isiklikud rakendused"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android töö jaoks"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android tööl"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tasulised teenused"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Tasuliste toimingute tegemine."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Teie sõnumid"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"seo häälinteraktsiooniga"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Lubab omanikul siduda häälinteraktsiooni teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"häältuvastuse võtmefraaside haldus"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Võimaldab omanikul hallata häältuvastuse otsetee sõna võtmefraase. Seda ei tohiks tavaliste rakenduste puhul kunagi vaja olla."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"kaugekraaniga sidumine"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"rakenduse käitamine tegevusetul ajal"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"See luba võimaldab Android-süsteemil käitada rakendust taustal siis, kui seadet ei kasutata."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"rakenduse ajastatud taustatoimingu käitamine"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"See luba võimaldab Android-süsteemil rakendust soovi korral taustal käitada."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Lubab rakendusel tuvastada muudatusi usaldusväärses olekus."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Usaldusväärse agendi esitamine."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Võimaldab rakendusel esitada usaldusväärset agenti."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Käivita usaldusväärse agendi seadete menüü."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Võimaldab rakendusel käivitada tegevuse, mis muudab usaldusväärse agendi käitumist."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Usaldusväärse agendi teenusega sidumine"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lubab rakendusel ennast siduda usaldusväärse agendi teenusega."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Suhtlemine värskenduse ja taastesüsteemiga"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 0d3289e..b4727bb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏سیستم Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"برنامه‌های شخصی"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"‏Android برای کار"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"سرویس‌های غیر رایگان"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"انجام کارهایی که برای شما هزینه دارد."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"پیام‌های شما"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"‏به دارنده اجازه می‎دهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامه‎های معمولی هرگز به این ویژگی نیاز ندارند."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"مقید بودن به سرویس تعامل صوتی"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"به دارنده امکان می‌دهد به واسط سطح بالای سرویس تعامل صوتی مقید باشد. برای برنامه‌های عادی هرگز نباید لازم باشد."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"مدیریت عبارات کلیدی صوتی"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"به دارنده امکان می‌دهد عبارات کلیدی برای شناسایی کلیدگفته صوتی را مدیریت کند. هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده ام‍ک‍ان می‌دهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامه‌های عادی لازم باشد."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"‏اجازه می‎دهد برنامه از هر رمزگشای رسانه نصب شده‌ای استفاده کند تا برای پخش رمزگشایی شود."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏به برنامه امکان می‌دهد گواهینامه‌های CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"اجرای برنامه در هنگام بدون فعالیت بودن دستگاه"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"‏این مجوز به سیستم Android امکان می‌دهد تا وقتی دستگاه استفاده نمی‌شود برنامه را در پس‌زمینه اجرا کند."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"اجرای کار پس‌زمینه زمان‌بندی شده برای برنامه"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"‏این مجوز، به سیستم Android امکان می‌دهد در صورت تقاضا، برنامه را در پس‌زمینه اجرا کند."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏به برنامه اجازه می‌دهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ به‌عنوان مثال، فایل‌های /dev. این امر به‌صورت بالقوه می‌تواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیص‎‌های مختص سخت‌افزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"‏به یک برنامه کاربردی برای گوش دادن به تغییرات در trust اجازه می‌دهد."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"یک عامل مورد اعتماد فراهم می‌آورد."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"به برنامه امکان می‌دهد یک عامل مورد اعتماد فراهم آورد."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"‏اتصال به یک سرویس trust agent"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"‏به یک برنامه کاربردی برای اتصال به یک سرویس trust agent اجازه می‌دهد."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"تعامل با سیستم به‌روزرسانی و بازیابی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1f4418c..02c6da4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -189,7 +189,8 @@
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Omat sovellukset"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android työkäyttöön"</string>
+    <!-- no translation found for managed_profile_label (4287077106125758391) -->
+    <skip />
     <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>
@@ -400,6 +401,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Antaa sovelluksen sitoutua taustakuvan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"puheohjauspalveluun sitominen"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Antaa sovelluksen luoda sidoksen puheohjauspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"puhuttujen ilmausten hallinta"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Sallii ilmausten hallinnan puhuttujen toimintosanojen tunnistusta varten. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"etänäyttöön sitoutuminen"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
@@ -445,8 +448,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"suorita sovellus laitteen ollessa käyttämättömänä"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Tämä oikeus sallii Android-järjestelmän siirtää sovelluksen suorituksen taustalle, kun laite ei ole käytössä."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"suorittaa sovelluksen ajoitetut taustatyöt"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Tämä antaa Android-järjestelmän suorittaa sovelluksen pyydettäessä taustalla."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
@@ -1360,6 +1363,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Antaa sovelluksen seurata luottamuksen tilamuutoksia."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Luotettavan tahon tarjoaminen"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Antaa sovelluksen tarjota luotettavan tahon."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Luotettavaan tahoon sitoutuminen"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Antaa sovelluksen sitoutua luotettavaan tahoon."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Vuorovaikutus päivitys- ja palautusjärjestelmän kanssa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 3b30f65..b1292b3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Applications personnelles"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android pour les activités professionnelles"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android pour les activités professionnelles"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"s\'associer à un service d\'interaction vocale"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'interaction vocale. Ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gérer les phrases clés vocales"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permet à l\'utilisateur de gérer les phrases clés pour la détection de mots clés vocaux. Cette option ne devrait jamais être nécessaire pour les applications standards."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"lier à un écran distant"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"exécuter le travail en arrière-plan planifié de l\'application"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan sur demande."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet à une application de détecter les modifications de l\'état de confiance."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fournir un agent de confiance."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permet à une application de fournir un agent de confiance."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Lier à un service d\'agent de confiance"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet à une application de se lier à un service d\'agent de confiance."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index abc8f9a..f511df0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Applications personnelles"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android pour les activités professionnelles"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"s\'associer à un service d\'interaction vocale"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'interaction vocale. Ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gérer les expressions clés vocales"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permettre à l\'application autorisée de gérer les expressions clés pour la détection de mots clés vocaux. Ne devrait jamais être nécessaire pour les applications standards."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"s\'associer à un écran à distance"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"exécuter les tâches en arrière-plan planifiées de l\'application"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan sur demande."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permettre à une application de détecter les modifications de l\'état de confiance."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fournir un agent de confiance"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permettre à une application de fournir un agent de confiance"</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"S\'associer à un service d\'agent de confiance"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permettre à une application de s\'associer à un service d\'agent de confiance."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index ef2205b..470ec41 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"व्यक्तिगत ऐप्स"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"कार्यालय के लिए Android"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android कार्य"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"वे सेवाएं जिन पर आप खर्चा करते हैं"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ऐसे कार्य करें जिससे आपका धन खर्च हो सकता है."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"आपके संदेश"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"किसी ध्वनि सहभागिताकर्ता से आबद्ध हों"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"धारक को किसी ध्वनि सहभागिता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ध्वनि कीफ़्रेज़ प्रबंधित करें"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"धारक को ध्वनि हॉटवर्ड पहचान के लिए कीफ़्रेज़ प्रबंधित करने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्‍तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स  को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स  को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"निष्क्रिय समय के दौरान एप्लिकेशन चलाएं"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"यह अनुमति Android सिस्टम को उपकरण के उपयोग में नहीं रहने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"एप्लिकेशन का शेड्यूल किया गया पृष्ठभूमि कार्य चलाएं"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"यह अनुमति Android सिस्टम को, अनुरोध किए जाने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्‍वामित्‍व वाले संसाधनों को पढ़ें/लिखें"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्‍वामित्‍व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्‍टम की स्‍थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"किसी एप्लिकेशन को ट्रस्ट स्थिति के बदलावों को सुनने की अनुमति देती है."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"विश्वसनीय एजेंट प्रदान करें."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"एप्लिकेशन को विश्वसनीय एजेंट प्रदान करने देती है."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"विश्वस्त एजेंट सेटिंग मेनू लॉन्च करें."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"एप्लिकेशन को ऐसी गतिविधि लॉन्च करने की अनुमति मिलती है जो विश्वस्त एजेंट के व्यवहार में बदलाव लाती है."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ट्रस्ट एजेंट सेवा से आबद्ध करना"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"किसी एप्लिकेशन को ट्रस्ट एजेंट सेवा से आबद्ध करने की अनुमति देती है."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"अपडेट और पुनर्प्राप्ति सिस्टम के साथ सहभागिता करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6badaac..7dc8e19 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Osobne aplikacije"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android za rad"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android za posao"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usluge koje se plaćaju"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Radite stvari koje će uzrokovati novčane troškove."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše poruke"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Nositelju omogućuje povezivanje sa sučeljem pozadinske slike najviše razine. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"povezivanje s uslugom glasovne interakcije"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge glasovne interakcije. Nije potrebno za normalne aplikacije."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"upravljanje glasovnim ključnim frazama"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Omogućuje korisniku upravljanje ključnim frazama za otkrivanje glasovnih pokretača značajke. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vezanje uz udaljeni zaslon"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"izvodi aplikaciju tijekom mirovanja"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dopuštenje omogućuje sustavu Android da izvodi aplikaciju u pozadini dok se uređaj ne upotrebljava."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"izvršavaj planirani rad aplikacije u pozadini"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"To dopuštenje omogućuje sustavu Android izvođenje aplikacije u pozadini na zahtjev."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
@@ -520,8 +522,8 @@
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogućuje aplikaciji primanje i preusmjeravanje audioizlaza."</string>
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otkrivanje pokretača značajke"</string>
     <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji omogućuje snimanje zvuka radi otkrivanja pokretača značajke. Snimanje se može odvijati u pozadini, ali ne sprječava drugo snimanje zvuka (npr. kameru)."</string>
-    <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Preusmjeravanje audija"</string>
-    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Omogućuje aplikaciji izravno upravljanje preusmjeravanjem audija i premošćivanje odluka pravila o audiju."</string>
+    <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Preusmjeravanje zvučnog zapisa"</string>
+    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Omogućuje aplikaciji izravno upravljanje preusmjeravanjem zvučnog zapisa i zaobilaženje odluka pravila o zvučnim zapisima."</string>
     <string name="permlab_captureVideoOutput" msgid="2246828773589094023">"primanje videoizlaza"</string>
     <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogućuje aplikaciji primanje i preusmjeravanje videoizlaza."</string>
     <string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"primanje sigurnog videoizlaza"</string>
@@ -1358,8 +1360,12 @@
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Omogućuje aplikaciji upravljanje zaključavanjem tipkovnice."</string>
     <string name="permlab_trust_listener" msgid="1765718054003704476">"Prati promjene pouzdanog stanja."</string>
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Omogućuje aplikaciji praćenje promjena pouzdanog stanja."</string>
-    <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Pružanje pouzdanog predstavnika."</string>
-    <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Omogućuje aplikaciji pružanje pouzdanog predstavnika."</string>
+    <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Pružanje agenta za pouzdanost."</string>
+    <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Omogućuje aplikaciji pružanje agenta za pouzdanost."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezivanje s uslugom pouzdanog predstavnika"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Omogućuje aplikaciji povezivanje s uslugom pouzdanog predstavnika."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakcija s ažuriranjem i sustavom za oporavak"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6d0ff1b..2582737 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Személyes alkalmazások"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android munkához"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Munkahelyi Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Fizetős szolgáltatások"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Olyan dolgok végrehajtása, amelyek pénzbe kerülnek."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Saját üzenetek"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy háttérkép legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"csatlakozás egy hangvezérlőhöz"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Lehetővé teszi a használó számára, hogy csatlakozzon egy hangvezérlő szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"hangalapú kulcskifejezések kezelése"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"A használó kezelheti a hangalapú hotwordök felismerésére szolgáló kulcskifejezéseket. Az átlagos alkalmazásoknak nem lehet rá szükségük."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"csatlakozás egy távoli kijelzőhöz"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"alkalmazás futtatása tétlen időszakban"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ezzel az engedéllyel az Android a háttérben futtathatja az alkalmazást, amikor az eszközt nem használják."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"az alkalmazás ütemezett műveleteinek futtatása a háttérben"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Az engedély lehetővé teszi az Android számára, hogy kérés esetén a háttérben futtassa az alkalmazást."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Lehetővé teszi, hogy az alkalmazás figyelje a trust-állapot változásait."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust agent szoftver megadása"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Lehetővé teszi, hogy az alkalmazás megadjon egy trust agent szoftvert."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Trust agent szoftver beállításmenüjének indítása."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Lehetővé teszi az alkalmazások számára olyan tevékenységek indítását, amelyek megváltoztatják a trust agent szoftver viselkedését."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Csatlakozás egy trust agent szolgáltatáshoz"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lehetővé teszi, hogy az alkalmazás egy trust agent szolgáltatáshoz csatlakozzon."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Kapcsolatfelvétel a frissítési és helyreállítási rendszerrel"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 5591bfb..f0bee2b 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Անձնական ​​ծրագրեր"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for Work"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Ծառայություններ, որոնց համար կգանձվեք"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Կատարել գործողություններ, որի դիմաց ձեր հաշվից գումար կծախսվի:"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Ձեր հաղորդագրությունները"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"կապվել ձայնային փոխազդիչին"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Թույլ է տալիս սեփականատիրոջը միանալ ձայնային փոխազդիչի բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"կառավարել ձայնային բանալի բառակապակցությունները"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Սեփականատիրոջը թույլ է տալիս կառավարել բանալի բառակապակցությունները՝ ձայնային թեժ բառերի հայտնաբերման համար: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"գործադրել ծրագրեր պարապուրդի ժամանակ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Այս թույլտվությունը հնարավորություն է տալիս, որ Android համակարգը ծրագրեր գործադրի ֆոնային ռեժիմում, երբ սարքը չի օգտագործվում:"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"աշխատեցնել ծրագրի ֆոնային ռեժիմում պլանավորված աշխատանքը"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Այս թույլտվության շնորհիվ Android համակարգն անհրաժեշտության դեպքում կարող է աշխատեցնել ծրագիրը ֆոնային ռեժիմում:"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ծրագրին թույլ է տալիս լսել վստահության կարգավիճակի փոփոխությունները:"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Տրամադրել վստահելի գործակալ:"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ծրագրին թույլ է տալիս տրամադրել վստահելի գործակալ:"</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Կապվել վստահելի գործակալի ծառայությանը"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 52da0cb..9dca8a5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplikasi pribadi"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android untuk Bekerja"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Layanan berbayar"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Lakukan hal yang dapat dikenai biaya."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Pesan Anda"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu wallpaper. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"mengikat ke pemicu interaksi suara"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan interaksi suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"mengelola frasa kunci suara"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Memungkinkan pemegang mengelola frasa kunci untuk deteksi kata cepat suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"mengikat ke layar jarak jauh"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"menjalankan aplikasi selama waktu nganggur"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat perangkat tidak digunakan."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"jalankan pekerjaan latar belakang yang terjadwal milik aplikasi"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat diminta."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Mengizinkan aplikasi mendengarkan perubahan dalam status kepercayaan."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Berikan agen tepercaya."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Memungkinkan aplikasi memberikan agen tepercaya."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Luncurkan menu setelan agen tepercaya."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Memungkinkan aplikasi meluncurkan aktivitas yang mengubah perilaku agen tepercaya."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Ikat ke layanan agen kepercayaan"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Mengizinkan aplikasi mengikat ke layanan agen kepercayaan."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan sistem pemulihan dan pembaruan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9ef396e..0ea6f6e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"App personali"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for Work"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servizi che prevedono un costo"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Svolgono operazioni che possono comportare un costo."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"I tuoi messaggi"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Consente l\'associazione di uno sfondo all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"collegamento a un servizio di interazione vocale"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di interazione vocale. Non dovrebbe essere mai necessaria per le normali app."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestione delle frasi chiave vocali"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Consente al titolare di gestire le frasi chiave per il rilevamento hotword vocale. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"collega a un display remoto"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"esegui l\'applicazione nel tempo di inattività del sistema"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background mentre il dispositivo non è in uso."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"esegui operazioni pianificate in background dell\'applicazione"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background quando richiesto."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Consente a un\'applicazione di rilevare le modifiche nello stato trust."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Indica un trust agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Consente a un\'applicazione di indicare un trust agent."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Avvio del menu di impostazioni del trust agent."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Consente a un\'applicazione di avviare un\'attività che modifica il comportamento del trust agent."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associazione a un servizio trust agent"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Consente a un\'applicazione di associarsi a un servizio trust agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interazione con il sistema di ripristino e aggiornamento"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index c7cbe56..19fb05a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏מערכת Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"אפליקציות אישיות"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"‏Android לעבודה"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"‏Android לעבודה"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"שירותים שעולים כסף"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ביצוע פעולות שעשויות לעלות לך כסף."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"ההודעות שלך"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"איגוד לשירות אינטראקציה קולית"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות אינטראקציה קולית. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ניהול של ביטויי מפתח קוליים"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"מאפשרת לבעלים לנהל את ביטויי המפתח עבור זיהוי של מילת הפעלה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"‏הכפפה לשירות Widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"הרצת אפליקציה בזמן מצב לא פעיל"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"‏ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהמכשיר אינו בשימוש."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"הרץ את העבודה ברקע המתוזמנת של האפליקציה"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"‏ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהפעולה מתבקשת."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"‏קרא/כתוב במשאבים בבעלות diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-‎/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"מאפשר לאפליקציה לחפש שינויים במצב אמון."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ציון סוכן אמון."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"מאפשר לאפליקציה לספק סוכן אמון."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"הפעלת תפריט ההגדרות של סוכן האמון."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"מאפשר לאפליקציה להתחיל פעילות המשנה את ההתנהגות של סוכן האמון."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"איגוד אל שירות סוכן אמון"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"מאפשר לאפליקציה לאגוד אל שירות סוכן אמון."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"אינטראקציה עם מערכת שחזור ועדכונים"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 281aaa9..6ba99bf 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"プライベートアプリ"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"ビジネス向けAndroid"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"料金の発生するサービス"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"料金発生の可能性がある操作を実行します。"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"送受信したメッセージ"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"音声対話サービスへのバインド"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"音声対話サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"音声キーフレーズの管理"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"音声注目ワードの認識用キーフレーズを管理することを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"アイドル状態でのアプリの実行"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"この権限により、端末が使用中でない場合でもAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"アプリの予定されたバックグラウンド作業の実行"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"この権限により、リクエストされるとAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"信頼状態の変更をリッスンすることをアプリに許可します。"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"信頼できるエージェントの提供"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"信頼できるエージェントの提供をアプリに許可します。"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"信頼できるエージェントの設定メニューの起動"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"信頼できるエージェントの動作を変更するアクティビティを開始することをアプリに許可します。"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"信頼できるエージェントサービスへのバインド"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"信頼できるエージェントサービスにバインドすることをアプリに許可します。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"アップデートと回復システムへのアクセス"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 01e68a2..879d00f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"პერსონალური აპები"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android სამსახურისთვის"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android სამსახურისთვის"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"სერვისები, რომელშიც ფულის გადახდა გიწევთ"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ისეთი აქტივობების განხორციელება, რომლებშიც ფულის გადახდა მოგიწევთ."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"თქვენი შეტყობინებები"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ხმის ინტერაქტორთან შეკავშირება"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"მფლობელს შეეძლება შეკავშირდეს ხმის ინტერაქციის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ხმოვანი საიდუმლო ფრაზების მართვა"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"საშუალებას აძლევს მფლობელს მართოს საიდუმლო ფრაზები ხმოვანი ჯადოსნური სიტყვის ამოცნობისათვის. ეს ჩვეულებრივ აპებს არ უნდა დაჭირდეს."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"უქმე მდგომარეობისას აპლიკაციის გაშვება"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ეს უფლება Android-ის სისტემას უფლებას ანიჭებს ფონურად გაუშვას აპლიკაცია, როდესაც მოწყობილობა არ გამოიყენება."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"აპლიკაციის დაგეგმილი ფონური სამუშაოს გაშვება"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"ეს ნებართვა Android-ის სისტემას საშუალებას აძლევს მოთხოვნისას ფონში გაუშვას აპლიკაცია."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"საშუალებას აძლევს აპლიკაციას მოუსმინოს ცვლილებებს სანდო მდგომარეობაში."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"სანდო აგენტის წარმოდგენა."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"საშუალებას აძლევს აპლიკაციას წარმოადგინოს სანდო აგენტი."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"სანდო აგენტის სერვისზე მიმაგრება."</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index ec389b1..daf004c 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ​​ Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"កម្មវិធី​ផ្ទាល់​ខ្លួន"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android សម្រាប់​ការងារ"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"សេវាកម្ម​ដែល​កាត់​លុយ​របស់​អ្នក"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ធ្វើ​អ្វី​ដែល​អាច​កាត់​លុយ​របស់​អ្នក។"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"សារ​របស់​អ្នក"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យ​ម្ចាស់​ចង​ចំណុចប្រទាក់​កម្រិត​កំពូល​នៃ​ផ្ទាំង​រូបភាព។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ភ្ជាប់​ទៅ​​អ្នក​សហការ​សំឡេង"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​​របស់​សេវាកម្ម​អន្តរកម្ម​សំឡេង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"គ្រប់គ្រង​ឃ្លា​សំឡេង"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​គ្រប់គ្រង​ឃ្លា​​សម្រាប់​​ការ​រក​ឃើញ​​​ពាក្យ​​ជា​សំឡេង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់​ទៅ​ការ​បង្ហាញ​ពី​ចម្ងាយ"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​ការ​បង្ហាញ​ពី​ចម្ងាយ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចង​សេវា​កម្ម​ធាតុ​ក្រាហ្វិក​"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ឲ្យ​កម្មវិធី​ប្រើ​កម្មវិធី​ឌិកូដ​មេឌៀ​ដែល​បាន​ដំឡើង ដើម្បី​ឌិកូដ​សម្រាប់​ការ​ចាក់​ឡើងវិញ។"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"គ្រប់គ្រង​ព័ត៌មាន​សម្ងាត់​ដែល​ទុកចិត្ត"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​ដំឡើង និង​លុប​វិញ្ញាបនបត្រ CA នៅ​ពេល​មាន​ព័ត៌មាន​សម្ងាត់​ដែល​ទុកចិត្ត។"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ដំណើរការ​កម្មវិធី​អំឡុង​ពេល​ទំនេរ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​ប្រព័ន្ធ Android ដំណើរការ​កម្មវិធី​ក្នុង​ផ្ទៃ​ខាង​ក្រោយ ខណៈ​ដែល​ឧបករណ៍​មិន​កំពុង​ប្រើ។"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"ដំណើរការ​ការងារ​ក្នុង​ផ្ទៃ​ខាង​ក្រោយ​ដែល​បាន​កំណត់​ពេលវេលា​សម្រាប់​​កម្មវិធី"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​ប្រព័ន្ធ Android ​ដំណើរ​ការ​កម្មវិធី​ក្នុង​ផ្ទៃ​ខាង​ក្រោយ​ពេល​បាន​ស្នើ។"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"អាន/សរសេរ​ធនធាន​គ្រប់គ្រង​ប្រអប់"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ឲ្យ​កម្មវិធី​អាន និង​សរសេរ​ប្រភព​ណាមួយ​ដែល​គ្រប់គ្រង​ដោយ​ក្រុម​អ្នក​វិនិច្ឆ័យ ឧទាហរណ៍ ឯកសារ​នៅ​ក្នុង /dev ។ វា​អាច​ប៉ះពាល់​យ៉ាង​ខ្លាំង​ដល់​ស្ថេរ​ភាព​ និង​សុវត្ថិភាព​ប្រព័ន្ធ។ វា​គួរ​ត្រូវ​បាន​ប្រើ​សម្រាប់​វិនិច្ឆ័យ​ផ្នែក​រឹង​ជាក់​លាក់​ដោយ​ក្រុមហ៊ុន​ផលិត ឬ​ប្រតិបត្តិ​ករ។"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"បិទ ឬ​បើក​សមាសធាតុ​កម្មវិធី"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"ឲ្យ​កម្មវិធី​ស្ដាប់​ការ​ផ្លាស់ប្ដូរ​ក្នុង​ស្ថានភាព​ដែល​​ទុកចិត្ត។"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ផ្ដល់​ភ្នាក់ងារ​ដែល​ទុកចិត្ត។"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ឲ្យ​កម្មវិធី​ផ្ដល់​ភ្នាក់ងារ​ដែល​ទុកចិត្ត។"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"ចាប់ផ្ដើម​ម៉ឺនុយ​ការ​កំណត់​ភ្នាក់ងារ​ជឿ​ទុកចិត្ត។"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"អនុញ្ញាត​ឲ្យ​​កម្មវិធី​ចាប់ផ្ដើម​សកម្ម​​ដែល​ផ្លាស់​ប្ដូរ​ឥរិយា​បថ​​ភ្នាក់ងារ​ជឿ​ទុកចិត្ត​​។"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ភ្ជាប់​ទៅ​សេវាកម្ម​ភ្នាក់ងារ​ដែល​ទុកចិត្ត"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ឲ្យ​កម្មវិធី​ភ្ជាប់​សេវាកម្ម​ភ្នាក់ងារ​ដែល​ទុក​ចិត្ត។"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"អន្តរកម្ម​ជា​មួយ​បច្ចុប្បន្នភាព និង​ប្រព័ន្ធ​សង្គ្រោះ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2d8d0cd..43d1b25 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"개인 앱"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"업무용 Android"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"요금이 부과되는 서비스"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"요금이 부과될 수 있는 작업을 수행할 수 있도록 합니다."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"음성 상호작용 서비스 사용"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"권한을 가진 프로그램이 음성 상호작용 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"음성 핵심문구 관리"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"권한을 가진 프로그램이 음성 핫워드 감지용 핵심문구를 관리할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"유휴 시간 동안 애플리케이션 실행"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"이 권한을 부여하면 기기를 사용하지 않는 동안 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"애플리케이션의 예약된 백그라운드 작업 실행"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"이 권한을 부여하면 요청이 있을 경우 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"애플리케이션이 Trust 상태에서의 변경사항을 수신할 수 있도록 허용합니다."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust Agent 제공"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"애플리케이션이 Trust Agent를 제공할 수 있도록 허용합니다."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Trust Agent 서비스에 연결"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"애플리케이션이 Trust Agent 서비스에 바인딩할 수 있도록 허용합니다."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string>
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes.xml
deleted file mode 100644
index 8c8f86c..0000000
--- a/core/res/res/values-large/themes.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<!--
-===============================================================
-                        PLEASE READ
-===============================================================
-
-The Holo themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
-                        PLEASE READ
-===============================================================
- -->
-<resources>
-    <style name="Theme.Holo.DialogWhenLarge"
-            parent="@android:style/Theme.Holo.Dialog.FixedSize">
-        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
-    </style>
-    <style name="Theme.Holo.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.Holo.Dialog.NoActionBar.FixedSize">
-        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
-    </style>
-    <style name="Theme.Holo.Light.DialogWhenLarge"
-            parent="@android:style/Theme.Holo.Light.Dialog.FixedSize">
-    </style>
-    <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
-    </style>
-
-    <style name="Theme.Material.DialogWhenLarge"
-            parent="@android:style/Theme.Material.Dialog.FixedSize">
-        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
-    </style>
-    <style name="Theme.Material.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.Material.Dialog.NoActionBar.FixedSize">
-        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
-    </style>
-    <style name="Theme.Material.Light.DialogWhenLarge"
-            parent="@android:style/Theme.Material.Light.Dialog.FixedSize">
-    </style>
-    <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.Material.Light.Dialog.NoActionBar.FixedSize">
-    </style>
-</resources>
diff --git a/core/res/res/values-large/themes_device_defaults.xml b/core/res/res/values-large/themes_device_defaults.xml
index d57e827..d252c27 100644
--- a/core/res/res/values-large/themes_device_defaults.xml
+++ b/core/res/res/values-large/themes_device_defaults.xml
@@ -31,18 +31,12 @@
 ===============================================================
  -->
 <resources>
-    <style name="Theme.DeviceDefault.DialogWhenLarge"
-            parent="@android:style/Theme.DeviceDefault.Dialog.FixedSize">
+    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Dialog.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
-    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
+    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge"
-            parent="@android:style/Theme.DeviceDefault.Light.Dialog.FixedSize">
-    </style>
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
-    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Light.Dialog.FixedSize" />
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize" />
 </resources>
diff --git a/core/res/res/values-large/themes_holo.xml b/core/res/res/values-large/themes_holo.xml
new file mode 100644
index 0000000..3f03932
--- /dev/null
+++ b/core/res/res/values-large/themes_holo.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Holo themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <style name="Theme.Holo.DialogWhenLarge" parent="@style/Theme.Holo.Dialog.FixedSize">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.Holo.DialogWhenLarge.NoActionBar" parent="@style/Theme.Holo.Dialog.NoActionBar.FixedSize">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.Holo.Light.DialogWhenLarge" parent="@style/Theme.Holo.Light.Dialog.FixedSize" />
+    <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize" />
+</resources>
diff --git a/core/res/res/values-large/themes_material.xml b/core/res/res/values-large/themes_material.xml
new file mode 100644
index 0000000..2781608
--- /dev/null
+++ b/core/res/res/values-large/themes_material.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material.Dialog.FixedSize">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Dialog.NoActionBar.FixedSize">
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+    <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize" />
+    <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index f7ae955..e386a24 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"​ແອັບຯ​ສ່ວນ​ໂຕ"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android ​ສຳ​ລັບ​ບ່ອນ​ເຮັດ​ວຽກ"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"ບໍລິການທີ່ເຮັດໃຫ້ທ່ານເສຍເງິນ"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ເຮັດສິ່ງທີ່ທ່ານຕ້ອງເສຍຄ່າໃຊ້ຈ່າຍ."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"ຂໍ້ຄວາມຂອງທ່ານ"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"​ເຊື່ອມ​ໂຍງ​ກັບ​ຕົວ​ຕິດ​ຕໍ່​ດ້ວຍ​ສຽງ"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ອະ​ນຸ​ຍາດ​ໃຫ້​ເຈົ້າ​ຂອງ​ເຊື່ອມ​ໂຍງ​ສ່ວນ​ຕິດ​ຕໍ່​ລະ​ດັບ​ສູງ​ສຸດຂອງ​ບໍ​ລິ​ການ​ການ​ຕິດ​ຕໍ່​ດ້ວຍ​ສຽງ."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ຈັດການລະຫັດສຽງ"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"ອະນຸຍາດ​ໃຫ້​ຈັດການລະຫັດ​ສຳລັບ​ການ​ກວດ​ພົບ​ຄຳ​ສັ່ງ​ສຽງ. ແອັບຯ​ທົ່ວໄປ​ບໍ່​ຄວນ​ຕ້ອງ​ໃຊ້."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະ​ນຸ​ຍາດ​ໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ເປີດ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ໃນ​ເວ​ລາ​ທີ່​ບໍ່​ເຮັດ​ວຽກ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ນີ້​ຈະ​ເປັນ​ການອ​ະ​ນຸ​ຍາດ​​ໃຫ້​ລະ​ບົບ Android ສາ​ມາດ​ເປີດ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ໃນ​ພື້ນຫຼັງໄດ້​ໃນ​ຂະ​ນະ​ທີ່​ອຸ​ປະ​ກອນບໍ່​​ຖືກ​ນຳ​ໃຊ້."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"ເປີດ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​​ເພື່ອ​ເຮັດ​ວຽກ​ຕາມ​ເວ​ລາ​ຢູ່ໃນ​ພື້ນຫຼັງ"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"​ສິດ​ນີ້​ອະ​ນຸ​ຍາດ​ໃຫ້​ລະ​ບົບ Android ສາ​ມາດ​ເປີດ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ໃນ​ພື້ນຫຼັງ​ເມື່ອ​ຖືກ​ຮ້ອງ​ຂໍ​ໄດ້."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ຕິດ​ຕາມ​​ການ​ປ່ຽນ​ແປງ​ໃນ​ສະ​ຖາ​ນະ​ການ​ເຊື່ອ​ຖື."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"​ລະ​ບຸ​ເອ​ເຈນ​ທີ່​ເຊື່ອ​ຖື​ໄດ້."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ລະ​ບຸ​ເອ​ເຈນ​ທີ່​ເຊື່ອ​ຖື​ໄດ້."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"ເປີດ​ເມ​ນູການ​ຕັ້ງ​ຄ່າ​ເອ​ເຈັນ​ທີ່​ເຊື່ອ​ຖື​ໄດ້​."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພລິ​ເຄ​ຊັນ​ເປີດ​ການ​ເຄື່ອນ​ໄຫວ​ທີ່​ປ່ຽນ​ແປງ​ພຶດ​ຕິ​ກຳ​ຂອງ​ເອ​ເຈັນ​ທີ່​ເຊື່ອ​ຖື​ໄດ້."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"​ເຊື່ອມ​ໂຍງ​ຫາ​ບໍ​ລິ​ການ​ຕົວ​ແທນ​ການ​ເຊື່ອ​ຖື"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນເຊື່ອມ​ໂຍງ​ກັບ​ບໍ​ລິ​ການ​ຕົວ​ແທນ​ທີ່​ເຊື່ອ​ຖື​ໄດ້."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"ຕິດຕໍ່ກັບລະບົບອັບເດດ ແລະລະບົບກູ້ຂໍ້ມູນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 5865662..be7e571 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
     <string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Asmeninės programos"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Darbui skirta „Android“"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"„Android“ (darbas)"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Paslaugos, už kurias mokėjote"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Atlikite mokamus veiksmus."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Jūsų pranešimai"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Leidžiama savininką susaistyti su aukščiausio lygio darbalaukio fono sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"susaistyti su sąveikos balsu priemone"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Turėtojui leidžiama susaistyti programą su sąveikos balsu paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"tvarkyti pagrindines balso frazes"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Savininkui leidžiama tvarkyti pagrindines aktyvinamiesiems žodžiams aptikti skirtas frazes. To niekada neturėtų prireikti naudojant įprastas programas."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"susisaistyti su nuotoliniu ekranu"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"paleisti programą, kai įrenginys yra neaktyvus"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Šiuo leidimu sistemai „Android“ leidžiama fone paleisti programą, kai įrenginys yra nenaudojamas."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"vykdyti suplanuotą programos darbą fone"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Šiuo leidimu sistemai „Android“ leidžiama fone vykdyti programą, kai to prašoma."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Programai leidžiama atsižvelgti į patikimos būsenos pakeitimus."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Teikti patikimos priemonės paslaugą."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Programai leidžiama teikti patikimos priemonės paslaugą."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Paleisti patikimo atstovo nustatymų meniu."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Leidžiama programai paleisti veiklą, keičiančią patikimo atstovo elgseną."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Susisaistyti su „trust agent“ paslauga"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Programai leidžiama susisaistyti su „trust agent“ paslauga."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Sąveikauti su naujiniu ir atkūrimo sistema"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8b69875..b421da4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Personīgās lietotnes"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android darbam"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android darbs"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Maksas pakalpojumi"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Veikt darbības, par kurām, iespējams, būs jāmaksā."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Jūsu ziņojumi"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ļauj īpašniekam piesaistīt tapetes augstākā līmeņa lietotāja saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Saistīšana ar balss mijiedarbības elementu"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ļauj īpašniekam izveidot savienojumu ar balss mijiedarbības pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"pārvaldīt balss atslēgas frāzes"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ļauj īpašniekam pārvaldīt atslēgas frāzes balss īsinājumvārdu identificēšanai. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Saites izveide ar attālu displeju"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"Lietojumprogrammas darbība dīkstāves laikā"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ar šo atļauju Android sistēmā lietojumprogramma darbojas fonā, kad ierīce netiek lietota."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"iespējot lietojumprogrammas plānoto darbību fonā"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Ar šo atļauju Android sistēmā lietojumprogramma pēc pieprasījuma darbojas fonā."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ļauj lietojumprogrammai klausīties uzticamības statusa izmaiņas."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Nodrošināt uzticamības pārbaudes programmu"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ļauj lietojumprogrammai nodrošināt uzticamības pārbaudes programmu."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Palaist uzticamības pārbaudes programmas iestatījumu izvēlni."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ļauj lietojumprogrammai palaist darbību, kas maina uzticamības pārbaudes programmas rīcību."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Izveidot savienojumu ar uzticamības pārbaudes pakalpojumu"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ļauj lietojumprogrammai izveidot savienojumu ar uzticamības pārbaudes pakalpojumu."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Mijiedarbošanās ar atjauninājumu un atkopšanas sistēmu"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 9f4028a..803128f 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Хувийн апп-ууд"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Ажилд зориулсан Андройд"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Андройд Ажил"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Танаас төлбөр авдаг үйлчилгээнүүд"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Таны төлбөрт оруулах зүйлийг хийх."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Таны мессеж"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"дуугаар харьцагчтай холбох"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Эзэмшигчид дуугаар харьцах үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"дууны гол хэллэгүүдийг удирдах"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Эзэмшигчид дууны хотворд-г таних гол хэллэгүүдийг удирдах боломж олгоно. Энгийн апп-д хэзээ ч ашиглагдахгүй."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"Сул зогсолтын хугацаанд аппликешнийг ажиллуулна"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг ашиглахгүй байгаа үед аппликешныг далд ажиллуулах боломж олгоно."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"аппликешны төлөвлөгдсөн далд ажлыг эхлүүлэх"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг хүсэлт гаргасан үед  аппликешныг далд ажиллуулах боломж олгоно."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын  нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Итгэмжлэлд орж буй өөрчлөлтийг мэдэх боломжийг аппликешнд олгоно."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Итгэмжлэгдсэн төлөөлөгч нийлүүлэх"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Аппликешнд итгэмжлэгдсэн төлөөлөгч нийлүүлэх боломж олгоно."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Итгэмжлэгдсэн агентын тохиргоо цэсийг эхлүүлэх."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Аппликешнд итгэмжлэгдсэн агентын авирыг өөрчлөх боломжтой үйлдлийг эхлүүлэхийг зөвшөөрнө."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Итгэмжлэгдсэн төлөөлөгчийн үйлчилгээтэй холбогдох"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Аппликешнд итгэмжлэгдсэн төлөөлөгчтэй холбогдох боломж олгоно."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Шинэчлэлт болон сэргээх системтэй харилцах"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 91c7c95..1d1a75b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -189,7 +189,8 @@
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Apl peribadi"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android untuk Kerja"</string>
+    <!-- no translation found for managed_profile_label (4287077106125758391) -->
+    <skip />
     <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>
@@ -400,6 +401,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"terikat kepada interaksi suara"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan interaksi suara. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"urus frasa kunci suara"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Membenarkan pemegang menguruskan frasa kunci untuk pengesahan sebutan laluan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
@@ -445,8 +448,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"jalankan aplikasi pada masa melahu"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang semasa peranti tidak digunakan."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"jalankan kerja latar belakang dijadualkan aplikasi"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang apabila diminta."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
@@ -521,7 +524,7 @@
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Pengesanan sebutan laluan"</string>
     <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Benarkan apl merakam audio untuk pengesahan Sebutan Laluan. Rakaman ini boleh berlaku di latar belakang tetapi tidak menghalang rakaman audio lain (cth. Kamkorder)."</string>
     <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Penghalaan Audio"</string>
-    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Membenarkan apl untuk mengawal penghalaan audio secara langsung dan mengatasi keputusan dasar audio."</string>
+    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Membenarkan apl untuk mengawal penghalaan audio secara langsung dan melangkau keputusan dasar audio."</string>
     <string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap output video"</string>
     <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Membenarkan apl menangkap dan mengubah hala output video."</string>
     <string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap output video selamat"</string>
@@ -1360,6 +1363,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Membenarkan aplikasi mendengar perubahan dalam keadaan amanah."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Sediakan ejen amanah."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Membenarkan aplikasi menyediakan ejen amanah."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Mengikat kepada perkhidmatan ejen amanah"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index dcc648e..31fa11d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Personlige apper"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for arbeidsplassen"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Betaltjenester"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gjøre ting som kan koste deg penger."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Meldinger"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lar innehaveren binde det øverste nivået av grensesnittet til en bakgrunn. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"binde seg til en tjeneste for talehandlinger"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en tjeneste for talehandlinger. Dette skal ikke være nødvendig for vanlige apper."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrer nøkkelfraser for stemmebruk"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Tillater innehaveren å administrere nøkkelfraser for gjenkjennelse av talekommandoord. Skal aldri være nødvendig for normale apper."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"binde til ekstern skjerm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"kjør appen når den ikke er i bruk"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen mens enheten ikke er i bruk."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"kjøre appens planlagte bakgrunnsprosesser"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen når det bes om det."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Gir appen tillatelse til å oppdage endringer i tillitsstatusen."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Angivelse av en pålitelig agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillater appen å angi en pålitelig agent."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Start innstillingsmenyen til tillitsagenten."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Tillater apper å starte en aktivitet som endrer atferden til tillitsagenter."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Tilknytt en tillitsagent-tjeneste."</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Gir appen tillatelse til å knyttes til en tillitsagent-tjeneste."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Samhandling med oppdateringer og gjenopprettingssystem"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 4815123..a655f36 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Persoonlijke apps"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android voor werk"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android werk"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services waarvoor u moet betalen"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Activiteiten uitvoeren waarvoor kosten in rekening kunnen worden gebracht."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Uw berichten"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Hiermee wordt de houder toegestaan zich te verbinden met de hoofdinterface van een achtergrond. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"binden aan een service voor spraakinteractie"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Hiermee kan de houder binden aan de hoofdinterface van een service voor spraakinteractie. Nooit vereist voor normale apps."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gesproken trefwoorden beheren"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Hiermee kan de houder de trefwoorden voor gesproken hotword-detectie beheren. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"verbinding maken met een extern display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"app uitvoeren tijdens inactiviteit"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren terwijl het apparaat niet wordt gebruikt."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"geplande achtergrondwerkzaamheden van de app uitvoeren"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren wanneer dit wordt gevraagd."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Toestaan dat een app controleert op wijzigingen in de trust-status."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Een trust-agent aanleveren."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Hiermee kan een app een trust-agent aanleveren."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Menu met instellingen voor vertrouwensagent starten."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Hiermee kan een app een activiteit starten waarmee het gedrag van de vertrouwensagent wordt gewijzigd."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Binden aan een trust-agentservice"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Toestaan dat een app wordt gebonden aan een trust-agentservice."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interactie met update- en herstelsysteem"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index cfbb622..c30ad74 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
     <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplikacje osobiste"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android w pracy"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android w pracy"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usługi płatne"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Wykonywanie czynności, za które pobierana jest opłata."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Twoje wiadomości"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu tapety. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"powiąż z interaktorem głosowym"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi interakcji głosowej. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"zarządzanie frazami głosowymi"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Pozwala zarządzać frazami używanymi do wykrywania słów-kluczy w komendach głosowych. Nie powinno być nigdy potrzebne w zwykłych aplikacjach."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"powiązanie z wyświetlaczem zdalnym"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"uruchom aplikację w czasie bezczynności"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To uprawnienie pozwala systemowi Android uruchomić aplikację w tle, gdy urządzenie nie jest używane."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"uruchom zaplanowane działania aplikacji w tle"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"To uprawnienie zezwala Androidowi na uruchamianie aplikacji w tle na jej żądanie."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Zezwala aplikacji na monitorowanie zmian w stanie zaufania."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Dostarczaj agenta zaufania."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Zezwala aplikacji na dostarczanie agenta zaufania."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Uruchom menu ustawień zaufanego agenta."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Umożliwia aplikacji uruchamianie czynności, która zmienia działanie zaufanego agenta."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Powiąż z usługą agenta zaufania"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Zezwala aplikacji na powiązanie z usługą agenta zaufania."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakcja z systemem odzyskiwania i aktualizacjami"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 0ddc2d3..2e4e423 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplicações pessoais"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android para trabalho"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Trabalho Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que implicam pagamento"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efetuar ações que implicam pagamento."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"As suas mensagens"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite ao titular vincular-se à interface de nível superior de uma imagem de fundo. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vincular a um interlocutor de voz"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o titular vincule a interface de nível superior de um serviço de interação de voz. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gerir expressões-chave de voz"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite ao proprietário gerir as expressões-chave para a deteção de palavras de ativação de voz. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"associar a um ecrã remoto"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"executar aplicação durante o tempo de inatividade"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano enquanto o dispositivo não estiver a ser utilizado."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"executar o trabalho em segundo plano da aplicação"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano quando solicitado."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que uma aplicação registe alterações no trust state."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fornecer um agente fidedigno."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que uma aplicação forneça um agente fidedigno."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular a um serviço de trust agent"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que uma aplicação fique vinculada a um serviço de trust agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de recuperação e de atualização"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1e36eaf..3df7ecb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplicativos pessoais"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android para o trabalho"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android para 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>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"associar a um interagente de voz"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o proprietário use a interface de nível superior de um serviço de interação de voz. Não deve ser necessário para aplicativos comuns."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gerenciar frases-chave de voz"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite ao titular gerenciar as frases-chave para detecção de hotword por voz. Isso nunca será necessário para aplicativos normais."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"executar o aplicativo durante o tempo ocioso"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Permite que o sistema Android execute o aplicativo em segundo plano enquanto o dispositivo não está em uso."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"executar as operações programadas do aplicativo em segundo plano"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Esta permissão permite ao sistema Android executar o aplicativo em segundo plano quando solicitado."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que o aplicativo detecte alterações no estado de confiança."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fornecer um agente de confiança."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que um aplicativo forneça um agente de confiança."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associar a um serviço de agente de confiança"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 9ba2fbe..ff26d8f 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -248,7 +248,7 @@
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <!-- no translation found for user_owner_label (6465364741001216388) -->
     <skip />
-    <!-- no translation found for managed_profile_label (3022906847647343112) -->
+    <!-- no translation found for managed_profile_label (4287077106125758391) -->
     <skip />
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servetschs che custan"</string>
     <!-- no translation found for permgroupdesc_costMoney (3293301903409869495) -->
@@ -634,6 +634,10 @@
     <skip />
     <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
     <skip />
+    <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
+    <skip />
+    <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
+    <skip />
     <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
     <skip />
     <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
@@ -722,9 +726,9 @@
     <skip />
     <!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
     <skip />
-    <!-- no translation found for permlab_bindIdleService (816311765497613780) -->
+    <!-- no translation found for permlab_bindJobService (3637568367978271086) -->
     <skip />
-    <!-- no translation found for permdesc_bindIdleService (1767538493214100612) -->
+    <!-- no translation found for permdesc_bindJobService (3473288460524119838) -->
     <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
     <!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
@@ -2186,6 +2190,10 @@
     <skip />
     <!-- no translation found for permdesc_provide_trust_agent (3865702641053068148) -->
     <skip />
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <!-- no translation found for permlab_bind_trust_agent_service (8242093169457695334) -->
     <skip />
     <!-- no translation found for permdesc_bind_trust_agent_service (7041930026024507515) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8ab8ccf..110b243 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -189,7 +189,8 @@
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Aplicații personale"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android pentru serviciu"</string>
+    <!-- no translation found for managed_profile_label (4287077106125758391) -->
+    <skip />
     <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>
@@ -400,6 +401,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"conectare la un serviciu de interacțiune vocală"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de interacțiune vocală. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestionarea expresiilor cheie vocale"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite titularului să gestioneze expresiile cheie pentru detectarea expresiei de activare. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
@@ -445,8 +448,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"rulează aplicația în timp ce dispozitivul este inactiv"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cu această permisiune, sistemul Android poate rula aplicația în fundal în timp ce dispozitivul nu este utilizat."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"rulează operațiile programate, în fundal, ale aplicației"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Cu această permisiune, sistemul Android poate rula aplicația în fundal la cerere."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
@@ -1360,6 +1363,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite unei aplicații să detecteze modificările în starea de încredere."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Indicați un agent de încredere."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite unei aplicații să indice un agent de încredere."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Asocierea la un serviciu „agenți de încredere”."</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite unei aplicații să se asocieze la un serviciu „agent de încredere”."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interacțiune cu sistemul de recuperare și de actualizare"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 17a0396..12d1895 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Персональные приложения"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android для бизнеса"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android для бизнеса"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платные услуги"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Приложение сможет использовать платные услуги."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Сообщения"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Подключение к службам голосового взаимодействия"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Приложение сможет подключаться к базовому интерфейсу служб голосового взаимодействия. Это разрешение обычно используется только специальными приложениями."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"Управление ключевыми фразами для распознавания голосовых команд"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Управление ключевыми фразами для функции распознавания голосовых команд. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"выполнение приложения в спящем режиме"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Система Android сможет выполнять приложение в фоновом режиме, когда устройство не используется."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"Запуск приложения в фоновом режиме по расписанию"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Запуск приложения в фоновом режиме по запросу."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Приложение сможет отслеживать изменения в статусе доверия."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Доверенный агент"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Предоставление доверенных агентов."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Запуск настроек Trust Agent"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Запуск меню, позволяющего управлять настройками Trust Agent."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Подключение к службе Trust Agents"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Приложение сможет подключаться к службе Trust Agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействовать с системой восстановления и обновлениями"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e98a4be..ab596c5 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Osobné aplikácie"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android na prácu"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android na prácu"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Spoplatnené služby"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Vykonávanie činností, ktoré vás môžu stáť peniaze."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše správy"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"viazanie na hlasovú interakciu"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby hlasovej interakcie. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"správa vyslovených kľúčových fráz"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Umožňuje držiteľovi spravovať kľúčové frázy pre rozpoznávanie vyslovených kľúčových slov. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"viazať na vzdialený displej"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"spustiť aplikáciu počas nečinnosti"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto povolenie umožňuje systému Android spustiť aplikáciu na pozadí, keď sa zariadenie nepoužíva."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"spustenie naplánovanej práce aplikácie na pozadí"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Toto povolenie umožňuje systému Android spustiť na základe požiadavky aplikáciu na pozadí."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikácii reagovať na zmeny stavu dôveryhodnosti."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Poskytnúť dôveryhodného agenta"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Umožňuje aplikácii poskytnúť dôveryhodného agenta."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Spustenie ponuky nastavení dôveryhodného agenta"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Umožňuje aplikácii spustiť aktivitu, ktorá zmení správanie dôveryhodného agenta."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Viazanie sa na službu zástupcu dôveryhodnosti"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikácii viazať sa na službu zástupcu dôveryhodnosti."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakcia so systémom aktualizácií a obnovenia"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 280e499..cc06fd3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Osebne aplikacije"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android za delo"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android – službeno"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Plačljive storitve"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dovolite stvari, za katere bo morda treba plačati."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Vaša sporočila"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Imetniku omogoča povezavo z vmesnikom ozadja najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"povezovanje z glasovnim interaktorjem"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Imetniku omogoča povezovanje z vmesnikom storitve glasovne interakcije najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"upravljanje glasovnih ključnih besednih zvez"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Imetniku omogoča upravljanje ključnih besednih zvez za zaznavanje sprožilne besede. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"povezava z oddaljenim prikazom"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"izvajanje aplikacije ob nedejavnosti"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dovoljenje sistemu Android omogoča, da izvaja aplikacijo v ozadju, ko naprava ni v uporabi."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"izvajanje načrtovanega dela aplikacije v ozadju"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"To dovoljenje sistemu Android omogoča, da na zahtevo izvaja aplikacijo v ozadju."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Aplikaciji dovoli spremljanje sprememb stanja zaupanja."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Navedba posrednika zaupanja."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Aplikaciji dovoli navesti posrednika zaupanja."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Odpri meni z nastavitvami posrednika zaupanja."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Dovoli aplikaciji zagon dejavnosti, ki spremeni način delovanja posrednika zaupanja."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezovanje s storitvijo posrednikov zaupanja"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Aplikaciji dovoli povezovanje s storitvijo posrednikov zaupanja."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Uporaba sistema za posodobitev in obnovitev"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6147fd8..099e6ef 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Личне апликације"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android за посао"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android за посао"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Услуге које се плаћају"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Покреће радње које могу да се плаћају."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Поруке"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"повежи са гласовним интерактором"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге гласовне интеракције. Не би требало никада да буде потребно за уобичајене апликације."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"управљање усменим кључним фразама"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Дозвољава власнику да управља кључним фразама за откривање усмених актуелних речи. Никада не би требало да буде потребно за уобичајене апликације."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"покреће апликације током неактивности"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ова дозвола омогућава систему Android да покреће апликације у позадини док се уређај не користи."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"покретање заказаних задатака апликације у позадини"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Ова дозвола омогућава систему Android да покреће апликацију у позадини на захтев."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозвољава апликацији да прати промене Trust стања."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Обезбеђивање поузданог агента."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Дозвољава апликацији да обезбеди поузданог агента."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Везивање за услугу Trust agents"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозвољава апликацији да се веже за услугу Trust agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Интеракција са системом за ажурирање и опоравак"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index acd5bee..46bb563 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Personliga appar"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android för arbetet"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android – arbete"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjänster som kostar pengar"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Göra saker som kan kosta pengar."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Dina meddelanden"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Innehavaren kan binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind till en röstkomponent"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en rösttjänst. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"hantera sökfraser för röstkommandon"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Innehavaren får hantera sökfraser för identifiering av röstkommandon. Detta ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind till en fjärrskärm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"kör appen när enheten är inaktiv"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med den här behörigheten tillåts Android-systemet att köra appen i bakgrunden när enheten inte används."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"kör appens schemalagda bakgrundsarbete"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Med den här behörigheten får Android-systemet köra appen i bakgrunden när detta begärs."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillåter att en app lyssnar efter ändringar i den betrodda agentens status."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Tillhandahåll en betrodd agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillåter att en app tillhandahåller en betrodd agent."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind till en tjänst från en betrodd agent"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillåter att en app binds vid en tjänst från en betrodd agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagera med uppdaterings- och återställningssystemet"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index b177516..595c807 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Programu binafsi"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android kwa Kazi"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Kazi ya Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Huduma ambazo zinakugharimu pesa"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Fanya mambo ambayo yanaweza kukugharimu pesa."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Ujumbe wako"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Inaruhusu kishikiliaji kushurutisha kwa kusano ya kiwango cha juu cha mandhari. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bandika kwenye mwingiliano wa sauti"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Humruhusu mmiliki kubandika kwenye kiolesura cha hali ya juu cha huduma ya muingiliano wa sauti. Isihitajike kamwe kwa programu za kawaida."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"Simamia misimbo kuu ya sauti"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Huruhusu mmiliki kusimamia misimbo kuu ya utambuzi wa neno tekelezi la sauti. Haipaswi kuhitajika kwa programu za kawaida kamwe."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"fungisha kwenye mwonekano wa mbali"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"endesha programu wakati kifaa hakifanyi kitu"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ruhusa hii huwezesha mfumo wa Android kuendesha programu chini kwa chini wakati kifaa hakitumiki."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"endesha kazi ya chini chini iliyopangwa ya programu"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Idhini hii huruhusu mfumo wa Android kuendesha programu chini chini ikipokea ombi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Huruhusu programu kusikiliza mabadiliko katika hali ya kuaminiwa."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Toa wakala wa uaminifu."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Huruhusu programu kutoa wakala wa uaminifu."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Funga kwenye huduma ya dalali wa kuaminiwa"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Huruhusu programu kufungamanisha kwenye huduma ya dalali wa kuaminiwa."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Ingiliana na sasisho na mfumo wa kurejesha"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c5ef006..feabf4f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ระบบแอนดรอยด์"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"แอปส่วนตัว"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"แอนดรอยด์สำหรับการทำงาน"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"แอนดรอยด์สำหรับการทำงาน"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"บริการที่ต้องเสียค่าใช้จ่าย"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ทำสิ่งที่คุณต้องเสียค่าใช้จ่าย"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"ข้อความของคุณ"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"เชื่อมโยงกับโปรแกรมโต้ตอบด้วยเสียง"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการโต้ตอบด้วยเสียง ไม่จำเป็นสำหรับแอปทั่วไป"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"จัดการเสียงพูดวลีคำหลัก"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"ให้ผู้ใช้อุปกรณ์สามารถจัดการวลีคำหลักสำหรับการตรวจหาเสียงพูดคำที่นิยม ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"เรียกใช้แอปพลิเคชันในระหว่างที่ไม่ได้ใช้งาน"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"สิทธิ์นี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในพื้นหลังขณะไม่ได้ใช้งานอุปกรณ์อยู่"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"เรียกใช้งานเบื้องหลังที่กำหนดเวลาไว้ของแอปพลิเคชัน"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"การอนุญาตนี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในเบื้องหลังเมื่อได้รับคำขอ"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"อนุญาตให้แอปพลิเคชันฟังการเปลี่ยนแปลงที่มีต่อสถานะความน่าเชื่อถือ"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"เสนอตัวแทนที่เชื่อถือได้"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ช่วยให้แอปพลิเคชันสามารถเสนอตัวแทนที่เชื่อถือได้"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"เปิดเมนูการตั้งค่าตัวแทนที่เชื่อถือได้"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"อนุญาตให้แอปพลิเคชันเปิดกิจกรรมที่เปลี่ยนพฤติกรรมตัวแทนที่เชื่อถือได้"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"อนุญาตให้แอปพลิเคชันผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"โต้ตอบกับการอัปเดตและระบบการกู้คืน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 84e83d3..13b629e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Mga personal na app"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android para sa Trabaho"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Mga serbisyong ginagastusan mo"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gumawa ng mga bagay na magpapagastos sa iyo."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Iyong mga mensahe"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng isang wallpaper. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"i-bind sa isang voice interactor"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Nagbibigay-daan sa may-hawak na i-bind ang top-level na interface ng isang serbisyo sa pakikipag-ugnayan gamit ang boses. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"pamahalaan ang mga keyphrase ng boses"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Pinapayagan ang holder na pamahalaan ang mga keyphrase para sa pagtukoy ng hotword ng boses. Hindi dapat kailanman kailanganin para sa mga normal na app."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"magpasaklaw sa isang remote na display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"paganahin ang application habang idle"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background habang hindi ginagamit ang device."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"patakbuhin ang nakaiskedyul na paggana sa background ng application"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background kapag hiniling."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Pinapayagan ang isang application na makinig para sa mga pagbabago sa estado ng trust."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Magbigay ng trust agent."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Pinapayagan ang isang application na magbigay ng trust agent."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Ilunsad ang menu ng mga setting ng trust agent."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Nagbibigay-daan sa isang application na maglunsad ng aktibidad na nagbabago sa pagkilos ng trust agent."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Sumailalim sa isang serbisyo ng trust agent"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Pinapayagan ang isang application na sumailalim sa isang serbisyo ng trust agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Makipag-ugnay sa system ng pag-update at pagbawi"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 04bec96..0c19b03 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Kişisel uygulamalar"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"İş için Android"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Size maliyet getirebilecek işlemler yapma."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cihazın sahibine, duvar kağıdının en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bir ses etkileşimi hizmetine bağlanma"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"İzin sahibinin, bir ses etkileşimi hizmetine ait üst düzey arayüze bağlanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"sesli anahtar ifadeleri yönet"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"İzin sahibine, söylenen özel kelimeleri algılamak için anahtar ifadeleri yönetme izni verir. Normal uygulamalar için hiçbir zaman gerekli olmamalıdır."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"uzak ekrana bağlan"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"boşta kaldığında uygulamayı çalıştır"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Bu izin, cihaz kullanımda değilken Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"uygulamanın planlanan arka plan işini çalıştır"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Bu izin, istendiğinde Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Bir uygulamanın, güven durumundaki değişiklikleri dinlemesine izin verir."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Güven aracısı sağlama."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Bir uygulamanın güven aracısı sağlamasına izin verir."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Güven aracı hizmetine bağlan"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Bir uygulamanın, güven aracı hizmetine bağlanmasına izin verir."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Güncelleme ve kurtarma sistemiyle etkileşim kur"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 648d625..0d56975b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Особисті додатки"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android для роботи"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android для бізнесу"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Служби, які потребують оплати"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Виконувати дії, які потребують оплати."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Ваші повідомл."</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"підключитися до служби голосової взаємодії"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби голосової взаємодії. Звичайні додатки ніколи не використовують цей дозвіл."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"керувати голосовими ключовими фразами"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Власник може керувати ключовими фразами, які розпізнаватимуться як голосові команди швидкого запуску. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"запускати додаток, коли пристрій неактивний"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли пристрій не використовується."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"планово запускати додаток у фоновому режимі"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли це потрібно."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозволяє додатку відстежувати зміни в стані довіри."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Призначення довірчого агента."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Додаток може призначати довірчого агента."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Запустити меню налаштувань довірчого агента"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Додаток може запускати функцію, яка змінює поведінку довірчого агента."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Прив’язуватися до служби довірчих агентів"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7ee9070..dd13b45 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Ứng dụng cá nhân"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android dành cho công việc"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Dịch vụ tính tiền của bạn"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Thực hiện những tác vụ mà bạn có thể phải trả tiền."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Tin nhắn của bạn"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của hình nền. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"liên kết với trình tương tác bằng giọng nói"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tương tác bằng giọng nói. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"quản lý cụm từ khóa bằng giọng nói"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Cho phép chủ sở hữu quản lý các cụm từ khóa để phát hiện từ nóng bằng giọng nói. Không bao giờ cần cho ứng dụng thông thường."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"liên kết với màn hình từ xa"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"chạy ứng dụng trong thời gian rảnh"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi thiết bị không được sử dụng."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"chạy công việc trong nền đã lên lịch của ứng dụng"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi được yêu cầu."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
@@ -1360,6 +1362,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Cho phép ứng dụng quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Cung cấp tác nhân đáng tin cậy."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Cho phép ứng dụng cung cấp tác nhân đáng tin cậy."</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Liên kết với một dịch vụ của đại lý đáng tin cậy"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Cho phép ứng dụng liên kết với một dịch vụ của đại lý đáng tin cậy."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Tương tác với hệ thống khôi phục và bản cập nhật"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 8d82a17..6052fb0 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -36,4 +36,8 @@
     <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
     <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
 
+    <!-- Number of notifications to keep in the notification service historical archive.
+         Reduced intentionally for watches to retain minimal memory footprint -->
+    <integer name="config_notificationServiceArchiveSize">1</integer>
+
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d37eddd..3a07366 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -189,7 +189,8 @@
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"个人应用"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android for Work"</string>
+    <!-- no translation found for managed_profile_label (4287077106125758391) -->
+    <skip />
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要您付费的服务"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"执行可能需要您付费的操作。"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"您的信息"</string>
@@ -400,6 +401,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"绑定到语音互动器"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允许应用绑定到语音互动服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理语音关键短语"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允许应用管理用于语音启动指令检测的关键短语。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
@@ -443,10 +446,10 @@
     <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"允许应用从系统的各个日志文件中读取信息。这样,应用就可以发现关于您手机使用情况的一般信息,其中可能包含个人信息或隐私信息。"</string>
     <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"使用任何媒体解码器进行播放"</string>
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
-    <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
-    <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"在设备处于闲置状态时运行应用"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"当设备处于闲置状态时,此权限允许Android系统在后台运行该应用。"</string>
+    <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的凭据"</string>
+    <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载CA证书(作为信任的凭据)。"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"运行应用的排定后台工作"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Android系统收到请求后会在后台运行具有此权限的应用。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
@@ -521,7 +524,7 @@
     <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"启动指令检测"</string>
     <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允许应用捕获音频以便检测语音启动指令。捕获操作会在后台进行,但不会妨碍其他音频捕获工具(例如摄像机)。"</string>
     <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"音频路由"</string>
-    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"允许应用直接控制音频路由以及覆盖音频政策决策。"</string>
+    <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"允许应用直接控制音频路由以及覆盖音频规范决策。"</string>
     <string name="permlab_captureVideoOutput" msgid="2246828773589094023">"捕获视频输出"</string>
     <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允许该应用捕获和重定向视频输出。"</string>
     <string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"捕获安全视频输出"</string>
@@ -770,7 +773,7 @@
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="1738585194601476694">"住宅"</item>
-    <item msgid="1359644565647383708">"单位"</item>
+    <item msgid="1359644565647383708">"工作"</item>
     <item msgid="7868549401053615677">"其他"</item>
     <item msgid="3145118944639869809">"自定义"</item>
   </string-array>
@@ -825,7 +828,7 @@
     <string name="postalTypeOther" msgid="2726111966623584341">"其他"</string>
     <string name="imTypeCustom" msgid="2074028755527826046">"自定义"</string>
     <string name="imTypeHome" msgid="6241181032954263892">"住宅"</string>
-    <string name="imTypeWork" msgid="1371489290242433090">"单位"</string>
+    <string name="imTypeWork" msgid="1371489290242433090">"工作"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"其他"</string>
     <string name="imProtocolCustom" msgid="6919453836618749992">"自定义"</string>
     <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
@@ -1360,6 +1363,10 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"允许应用检测信任状态的变化。"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理。"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允许应用提供信任的代理。"</string>
+    <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+    <skip />
+    <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+    <skip />
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"绑定至信任的代理服务"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a9e1770..8e290b5 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"個人應用程式"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android 企業版"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android 企業版"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"付費服務"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的操作或服務。"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"您的訊息"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面,但一般應用程式並不需要使用。"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理語音關鍵字句"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允許應用程式管理語音關鍵字句,用於偵測語音啟動字詞 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當您不使用裝置時,此權限允許 Android 系統在背景執行應用程式。"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"執行應用程式的預定背景作業"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"這項權限可讓 Android 系統於收到要求時在背景執行應用程式。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式聽取信任狀態的變更。"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理程式。"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允許應用程式提供信任的代理程式。"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"啟動信任的代理程式設定選單。"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"允許應用程式啟動可變更信任的代理程式行為的活動。"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"與更新和復原系統互動"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b1aaae7..6ab2b48 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"個人應用程式"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"Android 企業版"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"Android 企業版"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要額外費用的服務。"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的作業或服務。"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"您的簡訊"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面 (一般應用程式並不需要)。"</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理語音關鍵字句"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允許應用程式管理語音關鍵字句,用於偵測語音啟動字詞 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當裝置處於未使用狀態時,此權限允許 Android 系統在背景執行應用程式。"</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"執行應用程式的預定背景作業"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"這項權限可讓 Android 系統於收到要求時在背景執行應用程式。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式接聽信任狀態變更。"</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理程式。"</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允許應用程式提供信任的代理程式。"</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"啟動信任的代理程式設定選單。"</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"允許應用程式啟動可變更信任的代理程式行為的活動。"</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"與更新和還原系統互動"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 25ff769..07238c3 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -189,7 +189,7 @@
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
     <string name="user_owner_label" msgid="6465364741001216388">"Izinhlelo zokusebenza zomuntu siqu"</string>
-    <string name="managed_profile_label" msgid="3022906847647343112">"I-Android yomsebenzi"</string>
+    <string name="managed_profile_label" msgid="4287077106125758391">"I-Android Work"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Amasevisi abiza imali"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Yenza izinto ezingakudla imali."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Imiyalezo yakho"</string>
@@ -400,6 +400,8 @@
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"hlanganisa kusisebenzisani sezwi"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo sesevisi yokusebenzisana yezwi. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"phatha amabinzana angukhiye wezwi"</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ivumela isibambi ukuthi siphathe amabinzana angukhiye wokutholwa kwe-hotword yezwi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bophezela kusibonisi sesilawuli kude"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
@@ -445,8 +447,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"qalisa uhlelo lokusebenza ngesikhathi sokungenzi lutho"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva ngenkathi idivayisi ingasebenzi."</string>
+    <string name="permlab_bindJobService" msgid="3637568367978271086">"qalisa umsebenzi ongemuva oshejuliwe wohlelo lokusebenza"</string>
+    <string name="permdesc_bindJobService" msgid="3473288460524119838">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva uma icelwa."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
@@ -1360,6 +1362,8 @@
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ivumela uhlelo lokusebenza ukuthi lilalelele izinguquko kusimo sethemba."</string>
     <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Nikeza umsebenzeli owethembekile."</string>
     <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ivumela uhlelo lokusebenza ukunikeza umsebenzeli owethembekile."</string>
+    <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Qalisa imenyu yezilungiselelo zomsebenzeli wethemba."</string>
+    <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ivumela uhlelo lokusebenza ukuthi luqalise umsebenzi oguqula ukuziphatha komsebenzeli wethemba."</string>
     <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bophezela kusevisi yomenzeli wethemba"</string>
     <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ivumela uhlelo lokusebenza ukuthi libophezeleke kusevisi yomenzeli wethemba."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Ixhumana nesibuyekezo nesistimu yokutakula"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5b362fc..8d8f69e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -496,6 +496,12 @@
         <!-- Internal layout used internally for window decor -->
         <attr name="windowActionBarFullscreenDecorLayout" format="reference" />
 
+        <!-- The duration, in milliseconds, of the window background fade duration
+             when transitioning into or away from an Activity when called with an
+             Activity Transition. Corresponds to
+             {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
+        <attr name="windowTransitionBackgroundFadeDuration" format="integer"/>
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -828,6 +834,8 @@
         <attr name="preferenceFragmentPaddingSide" format="dimension" />
         <!-- Default style for switch preferences. -->
         <attr name="switchPreferenceStyle" format="reference" />
+        <!-- Default style for seekbar preferences. -->
+        <attr name="seekBarPreferenceStyle" format="reference" />
 
         <!-- ============================ -->
         <!-- Text selection handle styles -->
@@ -1813,6 +1821,11 @@
              Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
         <attr name="navigationBarColor" format="color" />
 
+        <!-- The duration, in milliseconds, of the window background fade duration
+             when transitioning into or away from an Activity when called with an
+             Activity Transition. Corresponds to
+             {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
+        <attr name="windowTransitionBackgroundFadeDuration" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2419,6 +2432,30 @@
 
         <!-- Sets the state-based animator for the View. -->
         <attr name="stateListAnimator" format="reference"/>
+
+        <!-- Tint to apply to the background. -->
+        <attr name="backgroundTint" format="color" />
+
+        <!-- Blending mode used to apply the background tint. -->
+        <attr name="backgroundTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3008,7 +3045,29 @@
         <!-- Indicates the initial checked state of this button. -->
         <attr name="checked" format="boolean" />
         <!-- Drawable used for the button graphic (e.g. checkbox, radio button, etc). -->
-        <attr name="button" format="reference"/>
+        <attr name="button" format="reference" />
+        <!-- Tint to apply to the button graphic. -->
+        <attr name="buttonTint" format="color" />
+        <!-- Blending mode used to apply the button graphic tint. -->
+        <attr name="buttonTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="CheckedTextView">
         <!-- Indicates the initial checked state of this text. -->
@@ -3093,6 +3152,28 @@
         <!-- Determines whether to measure all children or just those in
              the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
         <attr name="measureAllChildren" format="boolean" />
+        <!-- Tint to apply to the foreground. -->
+        <attr name="foregroundTint" format="color" />
+        <!-- Blending mode used to apply the foreground tint. -->
+        <attr name="foregroundTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="ExpandableListView">
         <!-- Indicator shown beside the group View. This can be a stateful Drawable. -->
@@ -3198,6 +3279,10 @@
         <!-- @hide The alpha value (0-255) set on the ImageView's drawable. Equivalent
              to calling ImageView.setAlpha(int), not the same as View.setAlpha(float). -->
         <attr name="drawableAlpha" format="integer" />
+        <!-- Tint to apply to the image. -->
+        <attr name="tint" />
+        <!-- Blending mode used to apply the image tint. -->
+        <attr name="tintMode" />
     </declare-styleable>
     <declare-styleable name="ToggleButton">
         <!-- The text for the button when it is checked. -->
@@ -3388,6 +3473,98 @@
         <!-- Defines if the associated drawables need to be mirrored when in RTL mode.
              Default is false -->
         <attr name="mirrorForRtl" format="boolean" />
+        <!-- Tint to apply to the progress indicator. -->
+        <attr name="progressTint" format="color" />
+        <!-- Blending mode used to apply the progress indicator tint. -->
+        <attr name="progressTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the progress indicator background. -->
+        <attr name="progressBackgroundTint" format="color" />
+        <!-- Blending mode used to apply the progress indicator background tint. -->
+        <attr name="progressBackgroundTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the secondary progress indicator. -->
+        <attr name="secondaryProgressTint" format="color" />
+        <!-- Blending mode used to apply the secondary progress indicator tint. -->
+        <attr name="secondaryProgressTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the indepterminate progress indicator. -->
+        <attr name="indeterminateTint" format="color" />
+        <!-- Blending mode used to apply the indeterminate progress indicator tint. -->
+        <attr name="indeterminateTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the background. -->
+        <attr name="backgroundTint" />
+        <!-- Blending mode used to apply the background tint. -->
+        <attr name="backgroundTintMode" />
     </declare-styleable>
 
     <declare-styleable name="SeekBar">
@@ -3397,6 +3574,28 @@
         <attr name="thumbOffset" format="dimension" />
         <!-- Whether to split the track and leave a gap for the thumb drawable. -->
         <attr name="splitTrack" format="boolean" />
+        <!-- Tint to apply to the button graphic. -->
+        <attr name="thumbTint" format="color" />
+        <!-- Blending mode used to apply the button graphic tint. -->
+        <attr name="thumbTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="StackView">
@@ -3859,8 +4058,11 @@
         <attr name="inputType" />
     </declare-styleable>
     <declare-styleable name="PopupWindow">
+        <!-- The background to use for the popup window. -->
         <attr name="popupBackground" format="reference|color" />
+        <!-- The animation style to use for the popup window. -->
         <attr name="popupAnimationStyle" format="reference" />
+        <!-- Whether the popup window should overlap its anchor view. -->
         <attr name="overlapAnchor" format="boolean" />
     </declare-styleable>
     <declare-styleable name="ViewAnimator">
@@ -4772,7 +4974,7 @@
     </declare-styleable>
 
     <!-- ========================== -->
-    <!--   Vector drawable class   -->
+    <!--   VectorDrawable class   -->
     <!-- ========================== -->
     <eat-comment />
 
@@ -4792,7 +4994,7 @@
         <attr name="height" />
     </declare-styleable>
 
-    <!-- Defines the group used in Vector Drawables. -->
+    <!-- Defines the group used in VectorDrawables. -->
     <declare-styleable name="VectorDrawableGroup">
         <!-- The Name of this group -->
         <attr name="name" />
@@ -4814,7 +5016,7 @@
         <attr name="alpha" />
     </declare-styleable>
 
-    <!-- Defines the path used in Vector Drawables. -->
+    <!-- Defines the path used in VectorDrawables. -->
     <declare-styleable name="VectorDrawablePath">
         <!-- The Name of this path -->
         <attr name="name" />
@@ -4855,6 +5057,25 @@
     </declare-styleable>
 
     <!-- ========================== -->
+    <!--   AnimatedVectorDrawable class   -->
+    <!-- ========================== -->
+    <eat-comment />
+
+    <!-- Define the AnimatedVectorDrawable. -->
+    <declare-styleable name="AnimatedVectorDrawable">
+        <!-- The static vector drawable. -->
+        <attr name="drawable" />
+    </declare-styleable>
+
+    <!-- Defines the target path or group used in the AnimatedVectorDrawable. -->
+    <declare-styleable name="AnimatedVectorDrawableTarget">
+        <!-- The name of this target path or group -->
+        <attr name="name" />
+        <!-- The animation for this target path or group -->
+        <attr name="animation" />
+    </declare-styleable>
+
+    <!-- ========================== -->
     <!-- Animation class attributes -->
     <!-- ========================== -->
     <eat-comment />
@@ -6390,6 +6611,16 @@
         <attr name="settingsActivity" />
     </declare-styleable>
 
+    <!-- Use <code>voice-enrollment-application</code>
+         as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
+         by the enrollment application.
+         Described here are the attributes that can be included in that tag. -->
+    <declare-styleable name="VoiceEnrollmentApplication">
+        <attr name="searchKeyphraseId" format="integer" />
+        <attr name="searchKeyphrase" format="string" />
+        <attr name="searchKeyphraseSupportedLocales" format="string" />
+    </declare-styleable>
+
     <!-- Attributes used to style the Action Bar. -->
     <declare-styleable name="ActionBar">
         <!-- The type of navigation to use. -->
@@ -6564,6 +6795,10 @@
         <attr name="disableDependentsState" />
     </declare-styleable>
 
+    <declare-styleable name="SeekBarPreference">
+        <attr name="layout" />
+    </declare-styleable>
+
     <!-- Use <code>tts-engine</code> as the root tag of the XML resource that
          describes a text to speech engine implemented as a subclass of
          {@link android.speech.tts.TextToSpeechService}.
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 9bf2ce8..9f6c7ad 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -135,7 +135,6 @@
     <color name="notification_action_legacy_color_filter">#ff555555</color>
 
     <color name="notification_media_action_bg">#00000000</color>
-    <color name="notification_media_info_bg">#40FFFFFF</color>
     <color name="notification_media_progress">#FFFFFFFF</color>
 
     <!-- Keyguard colors -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index fdbe0a0..7371d4e 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -27,10 +27,10 @@
 
     <color name="bright_foreground_material_dark">@color/white</color>
     <color name="bright_foreground_material_light">@color/black</color>
-    <!-- Black 50% -->
-    <color name="bright_foreground_disabled_material_dark">#80000000</color>
     <!-- White 50% -->
-    <color name="bright_foreground_disabled_material_light">#80ffffff</color>
+    <color name="bright_foreground_disabled_material_dark">#80ffffff</color>
+    <!-- Black 50% -->
+    <color name="bright_foreground_disabled_material_light">#80000000</color>
     <color name="bright_foreground_inverse_material_dark">@color/bright_foreground_material_light</color>
     <color name="bright_foreground_inverse_material_light">@color/bright_foreground_material_dark</color>
 
@@ -89,6 +89,9 @@
     <color name="material_teal_A200">#ff18ffff</color>
     <color name="material_teal_A400">#ff00e5ff</color>
 
+    <!-- Accent color used by Settings -->
+    <color name="material_dark_teal_A400">#ff009688</color>
+
     <color name="material_green_100">#ffb7e1cd</color>
     <color name="material_green_300">#ff57bb8a</color>
     <color name="material_green_500">#ff0f9d58</color>
@@ -143,7 +146,10 @@
     <color name="material_blue_grey_600">#ff546e7a</color>
     <color name="material_blue_grey_700">#ff455a64</color>
     <color name="material_blue_grey_800">#ff37474f</color>
+    <!-- Primary color used by Settings -->
     <color name="material_blue_grey_900">#ff263238</color>
+    <!-- Primary dark color used by Settings -->
+    <color name="material_blue_grey_950">#ff21272b</color>
 
     <color name="material_brown_100">#ffd7ccc8</color>
     <color name="material_brown_300">#ffa1887f</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5555cf6..a4f78bd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -589,7 +589,7 @@
 
     <!-- Display low battery warning when battery level dips to this value.
          Also, the battery stats are flushed to disk when we hit this level.  -->
-    <integer name="config_criticalBatteryWarningLevel">4</integer>
+    <integer name="config_criticalBatteryWarningLevel">5</integer>
 
     <!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. -->
     <integer name="config_shutdownBatteryTemperature">680</integer>
@@ -597,8 +597,9 @@
     <!-- Display low battery warning when battery level dips to this value -->
     <integer name="config_lowBatteryWarningLevel">15</integer>
 
-    <!-- Close low battery warning when battery level reaches this value -->
-    <integer name="config_lowBatteryCloseWarningLevel">20</integer>
+    <!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel
+         plus this -->
+    <integer name="config_lowBatteryCloseWarningBump">5</integer>
 
     <!-- Default color for notification LED. -->
     <color name="config_defaultNotificationColor">#ffffffff</color>
@@ -627,6 +628,9 @@
     <!-- Default value for LED off time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOff">2875</integer>
 
+    <!-- Number of notifications to keep in the notification service historical archive -->
+    <integer name="config_notificationServiceArchiveSize">250</integer>
+
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
 
@@ -787,6 +791,19 @@
          config_enableFusedLocationOverlay is false. -->
     <string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
 
+    <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be
+         replaced by an app at run-time. When disabled, only the
+         config_hardwareFlpPackageName package will be searched for Hardware Flp,
+         otherwise packages whose signature matches the signatures of
+         config_locationProviderPackageNames will be searched, and the service
+         with the highest version number will be picked. Anyone who wants to
+         disable the overlay mechanism can set it to false.
+         -->
+    <bool name="config_enableHardwareFlpOverlay" translatable="false">true</bool>
+    <!-- Package name providing Hardware Flp. Used only when
+         config_enableHardwareFlpOverlay is false. -->
+    <string name="config_hardwareFlpPackageName" translatable="false">com.android.location.fused</string>
+
     <!-- Whether to enable geocoder overlay which allows geocoder to be replaced
          by an app at run-time. When disabled, only the
          config_geocoderProviderPackageName package will be searched for
@@ -1557,4 +1574,28 @@
         <item>users</item>
     </string-array>
 
+    <!-- default telephony hardware configuration for this platform.
+    -->
+    <!-- this string array should be overridden by the device to present a list
+         telephony hardware resource.  this is used by the telephony device controller
+         (TDC) to offer the basic capabilities of the hardware to the telephony
+         framework
+    -->
+    <!-- an array of "[hardware type],[hardware-uuid],[state],[[hardware-type specific]]"
+         with, [[hardware-type specific]] in:
+            - "[[ril-model],[rat],[max-active-voice],[max-active-data],[max-active-standby]]"
+              for 'modem' hardware
+            - "[[associated-modem-uuid]]"
+              for 'sim' hardware.
+         refer to HardwareConfig in com.android.internal.telephony for specific details/values
+         those elements can carry.
+    -->
+    <string-array translatable="false" name="config_telephonyHardware">
+        <!-- modem -->
+        <item>"0,modem,0,0,0,1,1,1"</item>
+        <!-- sim -->
+        <item>"1,sim,0,modem"</item>
+    </string-array>
+
+
 </resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index be7e6c1..18e4574 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -15,6 +15,11 @@
 -->
 <resources>
 
+    <!-- Preference fragment padding, sides -->
+    <dimen name="preference_fragment_padding_side_material">0dp</dimen>
+
+    <dimen name="preference_screen_header_padding_side_material">0dp</dimen>
+
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height_material">56dp</dimen>
     <!-- Default padding of an action bar. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8f3ee60..1580d69 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2185,6 +2185,27 @@
   <public type="attr" name="translateY" />
   <public type="attr" name="selectableItemBackgroundBorderless" />
   <public type="attr" name="elegantTextHeight" />
+  <public type="attr" name="searchKeyphraseId" />
+  <public type="attr" name="searchKeyphrase" />
+  <public type="attr" name="searchKeyphraseSupportedLocales" />
+  <public type="attr" name="windowTransitionBackgroundFadeDuration" />
+  <public type="attr" name="overlapAnchor" />
+  <public type="attr" name="progressTint" />
+  <public type="attr" name="progressTintMode" />
+  <public type="attr" name="progressBackgroundTint" />
+  <public type="attr" name="progressBackgroundTintMode" />
+  <public type="attr" name="secondaryProgressTint" />
+  <public type="attr" name="secondaryProgressTintMode" />
+  <public type="attr" name="indeterminateTint" />
+  <public type="attr" name="indeterminateTintMode" />
+  <public type="attr" name="backgroundTint" />
+  <public type="attr" name="backgroundTintMode" />
+  <public type="attr" name="foregroundTint" />
+  <public type="attr" name="foregroundTintMode" />
+  <public type="attr" name="buttonTint" />
+  <public type="attr" name="buttonTintMode" />
+  <public type="attr" name="thumbTint" />
+  <public type="attr" name="thumbTintMode" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2248,6 +2269,8 @@
   <public type="style" name="TextAppearance.Material.Widget.TextView.PopupMenu" />
   <public type="style" name="TextAppearance.Material.Widget.TextView.SpinnerItem" />
 
+  <public type="style" name="Theme.DeviceDefault.Settings" />
+
   <public type="style" name="Theme.Material" />
   <public type="style" name="Theme.Material.Dialog" />
   <public type="style" name="Theme.Material.Dialog.MinWidth" />
@@ -2261,6 +2284,7 @@
   <public type="style" name="Theme.Material.NoActionBar.Overscan" />
   <public type="style" name="Theme.Material.NoActionBar.TranslucentDecor" />
   <public type="style" name="Theme.Material.Panel" />
+  <public type="style" name="Theme.Material.Settings" />
   <public type="style" name="Theme.Material.Voice" />
   <public type="style" name="Theme.Material.Wallpaper" />
   <public type="style" name="Theme.Material.Wallpaper.NoTitleBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 23a117f..6e1b5ef 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -460,7 +460,7 @@
     <string name="user_owner_label">Personal apps</string>
 
     <!-- Label for a corporate profile in the intent forwarding app. -->
-    <string name="managed_profile_label">Android for Work</string>
+    <string name="managed_profile_label">Android Work</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
@@ -1122,6 +1122,12 @@
         interface of a voice interaction service. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_manageVoiceKeyphrases">manage voice keyphrases</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_manageVoiceKeyphrases">Allows the holder to manage the keyphrases for voice hotword detection.
+        Should never be needed for normal apps.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindRemoteDisplay">bind to a remote display</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
@@ -1261,10 +1267,10 @@
          permission that an application must be granted by the user.  Instead, it
          is part of a mechanism that applications use to indicate to the system
          that they want to do scheduled background work.  -->
-    <string name="permlab_bindTaskService">run the application\'s scheduled background work</string>
+    <string name="permlab_bindJobService">run the application\'s scheduled background work</string>
     <!-- Description of an application permission, so that the user can understand
          what is being done if they are curious. -->
-    <string name="permdesc_bindTaskService">This permission allows the Android system to run the application in the background when requested.</string>
+    <string name="permdesc_bindJobService">This permission allows the Android system to run the application in the background when requested.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_diagnostic">read/write to resources owned by diag</string>
@@ -3789,6 +3795,8 @@
     <string name="permlab_provide_trust_agent">Provide a trust agent.</string>
     <!-- Description of an application permission that lets it provide a trust agent. -->
     <string name="permdesc_provide_trust_agent">Allows an application to provide a trust agent.</string>
+    <string name="permlab_launch_trust_agent_settings">Lunch trust agent settings menu.</string>
+    <string name="permdesc_launch_trust_agent_settings">Allows an application to lunch an activity that changes the trust agent behavior.</string>
 
     <!-- Title of an application permission that lets it bind to a trust agent service. -->
     <string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5bd6122..d6be3133 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -980,6 +980,10 @@
         <item name="android:switchTextOff">@android:string/capital_off</item>
     </style>
 
+    <style name="Preference.SeekBarPreference">
+        <item name="android:layout">@android:layout/preference_widget_seekbar</item>
+    </style>
+
     <style name="Preference.PreferenceScreen">
     </style>
 
@@ -1035,6 +1039,10 @@
         <item name="android:switchTextOff">@android:string/capital_off</item>
     </style>
 
+    <style name="Preference.Holo.SeekBarPreference">
+        <item name="android:layout">@android:layout/preference_widget_seekbar</item>
+    </style>
+
     <style name="Preference.Holo.PreferenceScreen">
     </style>
 
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 84dbc79..84d38ce 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -254,6 +254,7 @@
     <style name="Preference.DeviceDefault.PreferenceScreen" parent="Preference.Material.PreferenceScreen"/>
     <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Material.RingtonePreference"/>
     <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Material.SwitchPreference"/>
+    <style name="Preference.DeviceDefault.SeekBarPreference" parent="Preference.Material.SeekBarPreference"/>
 
     <!-- AlertDialog Styles -->
     <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Material"/>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 92cce25..25307b9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -37,8 +37,8 @@
     </style>
 
     <style name="PreferenceFragment.Material">
-        <item name="paddingStart">@dimen/preference_fragment_padding_side</item>
-        <item name="paddingEnd">@dimen/preference_fragment_padding_side</item>
+        <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
+        <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
     </style>
 
     <style name="Preference.Material.Information">
@@ -64,6 +64,10 @@
         <item name="switchTextOff">@string/capital_off</item>
     </style>
 
+    <style name="Preference.Material.SeekBarPreference">
+        <item name="layout">@android:layout/preference_widget_seekbar_material</item>
+    </style>
+
     <style name="Preference.Material.PreferenceScreen"/>
 
     <style name="Preference.Material.DialogPreference">
@@ -86,6 +90,38 @@
         <item name="showDefault">true</item>
     </style>
 
+    <!-- No margins or background by default. Could be different for x-large screens -->
+    <style name="PreferencePanel.Material">
+    </style>
+
+    <!-- The attributes are overridden here because the x-large or large resources may have
+         changed the margins and background in the parent PreferencePanel style. -->
+    <style name="PreferencePanel.Material.Dialog">
+        <item name="layout_marginStart">0dip</item>
+        <item name="layout_marginEnd">0dip</item>
+        <item name="layout_marginTop">0dip</item>
+        <item name="layout_marginBottom">0dip</item>
+        <item name="background">@null</item>
+    </style>
+
+    <style name="PreferenceHeaderPanel.Material">
+        <item name="layout_marginStart">@dimen/preference_screen_side_margin</item>
+        <item name="layout_marginEnd">@dimen/preference_screen_side_margin_negative</item>
+        <item name="paddingTop">@dimen/preference_screen_header_vertical_padding</item>
+        <item name="paddingBottom">@dimen/preference_screen_header_vertical_padding</item>
+    </style>
+
+    <style name="PreferenceHeaderList.Material">
+        <item name="paddingStart">@dimen/preference_screen_header_padding_side_material</item>
+        <item name="paddingEnd">@dimen/preference_screen_header_padding_side_material</item>
+        <item name="scrollbarStyle">@integer/preference_screen_header_scrollbarStyle</item>
+    </style>
+
+    <style name="PreferenceFragmentList.Material">
+        <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
+        <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+    </style>
+
     <!-- Begin Material theme styles -->
 
     <!-- Text styles -->
@@ -344,7 +380,9 @@
         <item name="android:textColor">#66000000</item>
     </style>
 
-    <style name="Widget.StatusBar.Material.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal">
+    <style name="Widget.StatusBar.Material.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
+
+    <style name="Widget.StatusBar.Material.ProgressBar.Media">
         <item name="android:progressDrawable">@drawable/notification_material_media_progress</item>
     </style>
 
@@ -622,6 +660,7 @@
 
     <style name="Widget.Material.Spinner.DropDown.ActionBar">
         <item name="background">@drawable/spinner_background_material</item>
+        <item name="overlapAnchor">true</item>
     </style>
 
     <style name="Widget.Material.TabWidget" parent="Widget.TabWidget">
@@ -960,12 +999,17 @@
     <!-- Window title -->
     <style name="WindowTitleBackground.Material">
         <item name="background">@null</item>
+        <item name="paddingStart">16dp</item>
+        <item name="paddingEnd">16dp</item>
+        <item name="paddingTop">16dp</item>
     </style>
 
     <style name="WindowTitle.Material">
         <item name="singleLine">true</item>
         <item name="textAppearance">@style/TextAppearance.Material.WindowTitle</item>
         <item name="shadowRadius">0</item>
+        <item name="ellipsize">end</item>
+        <item name="textAlignment">viewStart</item>
     </style>
 
     <style name="DialogWindowTitle.Material">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2ea7421..5f4553b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -999,6 +999,7 @@
   <java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
   <java-symbol type="array" name="config_callBarringMMI" />
   <java-symbol type="array" name="config_globalActionsList" />
+  <java-symbol type="array" name="config_telephonyHardware" />
 
   <java-symbol type="drawable" name="default_wallpaper" />
   <java-symbol type="drawable" name="indicator_input_error" />
@@ -1122,6 +1123,15 @@
   <java-symbol type="drawable" name="ic_corp_badge" />
   <java-symbol type="drawable" name="ic_corp_icon_badge" />
 
+  <java-symbol type="drawable" name="sim_light_blue" />
+  <java-symbol type="drawable" name="sim_light_green" />
+  <java-symbol type="drawable" name="sim_light_orange" />
+  <java-symbol type="drawable" name="sim_light_purple" />
+  <java-symbol type="drawable" name="sim_dark_blue" />
+  <java-symbol type="drawable" name="sim_dark_green" />
+  <java-symbol type="drawable" name="sim_dark_orange" />
+  <java-symbol type="drawable" name="sim_dark_purple" />
+
   <java-symbol type="layout" name="action_bar_home" />
   <java-symbol type="layout" name="action_bar_title_item" />
   <java-symbol type="layout" name="action_menu_item_layout" />
@@ -1462,6 +1472,7 @@
   <java-symbol type="bool" name="config_animateScreenLights" />
   <java-symbol type="bool" name="config_automatic_brightness_available" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
+  <java-symbol type="bool" name="config_enableHardwareFlpOverlay" />
   <java-symbol type="bool" name="config_enableGeocoderOverlay" />
   <java-symbol type="bool" name="config_enableGeofenceOverlay" />
   <java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
@@ -1509,7 +1520,7 @@
   <java-symbol type="integer" name="config_defaultNotificationLedOn" />
   <java-symbol type="integer" name="config_deskDockKeepsScreenOn" />
   <java-symbol type="integer" name="config_lightSensorWarmupTime" />
-  <java-symbol type="integer" name="config_lowBatteryCloseWarningLevel" />
+  <java-symbol type="integer" name="config_lowBatteryCloseWarningBump" />
   <java-symbol type="integer" name="config_lowBatteryWarningLevel" />
   <java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
   <java-symbol type="integer" name="config_networkTransitionTimeout" />
@@ -1518,6 +1529,7 @@
   <java-symbol type="integer" name="config_notificationsBatteryLedOn" />
   <java-symbol type="integer" name="config_notificationsBatteryLowARGB" />
   <java-symbol type="integer" name="config_notificationsBatteryMediumARGB" />
+  <java-symbol type="integer" name="config_notificationServiceArchiveSize" />
   <java-symbol type="integer" name="config_radioScanningTimeout" />
   <java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
@@ -1552,6 +1564,7 @@
   <java-symbol type="string" name="chooser_wallpaper" />
   <java-symbol type="string" name="config_datause_iface" />
   <java-symbol type="string" name="config_fusedLocationProviderPackageName" />
+  <java-symbol type="string" name="config_hardwareFlpPackageName" />
   <java-symbol type="string" name="config_geocoderProviderPackageName" />
   <java-symbol type="string" name="config_geofenceProviderPackageName" />
   <java-symbol type="string" name="config_networkLocationProviderPackageName" />
@@ -1678,7 +1691,6 @@
   <java-symbol type="drawable" name="notification_material_bg" />
   <java-symbol type="drawable" name="notification_material_media_progress" />
   <java-symbol type="color" name="notification_media_action_bg" />
-  <java-symbol type="color" name="notification_media_info_bg" />
   <java-symbol type="color" name="notification_media_progress" />
   <java-symbol type="id" name="media_action_area" />
 
@@ -1881,5 +1893,6 @@
   <java-symbol type="color" name="timepicker_default_selector_color_material" />
   <java-symbol type="color" name="timepicker_default_numbers_background_color_material" />
   <java-symbol type="style" name="TextAppearance.Material.TimePicker.TimeLabel" />
+  <java-symbol type="attr" name="seekBarPreferenceStyle" />
 
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index cb5cb0c..5eec197 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -321,6 +321,7 @@
         <item name="preferenceInformationStyle">@android:style/Preference.Information</item>
         <item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@android:style/Preference.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@android:style/Preference.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item>
         <item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item>
@@ -1203,6 +1204,7 @@
         <item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item>
         <item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@android:style/Preference.Holo.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@android:style/Preference.Holo.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item>
         <item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item>
@@ -1543,6 +1545,7 @@
         <item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item>
         <item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@android:style/Preference.Holo.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@android:style/Preference.Holo.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item>
         <item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 6b7d861..8e83e48 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -160,6 +160,7 @@
         <item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
         <item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@style/Preference.DeviceDefault.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
         <item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
@@ -421,6 +422,7 @@
         <item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
         <item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@style/Preference.DeviceDefault.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
         <item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
@@ -555,4 +557,7 @@
 
     <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar" />
 
+    <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
+    <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings" />
+
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 1304d2b..77e4307 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -154,7 +154,7 @@
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
         <item name="windowTitleStyle">@style/WindowTitle.Material</item>
-        <item name="windowTitleSize">25dip</item>
+        <item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
         <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
         <item name="windowContentTransitions">false</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
@@ -277,17 +277,22 @@
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
         <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
-        <item name="preferenceFragmentPaddingSide">0dip</item>
         <item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
         <item name="preferenceStyle">@style/Preference.Material</item>
         <item name="preferenceInformationStyle">@style/Preference.Material.Information</item>
         <item name="checkBoxPreferenceStyle">@style/Preference.Material.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@style/Preference.Material.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@style/Preference.Material.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@style/Preference.Material.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@style/Preference.Material.DialogPreference</item>
         <item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
         <item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
         <item name="preferenceLayoutChild">@layout/preference_child_material</item>
+        <item name="preferencePanelStyle">@style/PreferencePanel.Material</item>
+        <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel.Material</item>
+        <item name="preferenceListStyle">@style/PreferenceHeaderList.Material</item>
+        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
+        <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
         <item name="detailsElementBackground">?attr/colorBackground</item>
 
         <!-- Search widget styles -->
@@ -503,7 +508,7 @@
         <item name="windowContentOverlay">@drawable/ab_solid_shadow_material</item>
         <item name="windowShowWallpaper">false</item>
         <item name="windowTitleStyle">@style/WindowTitle.Material</item>
-        <item name="windowTitleSize">25dip</item>
+        <item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
         <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
         <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
@@ -513,6 +518,9 @@
         <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
         <item name="statusBarColor">?attr/colorPrimaryDark</item>
         <item name="navigationBarColor">@color/black</item>
+        <item name="windowEnterTransition">@transition/fade</item>
+        <item name="windowSharedElementEnterTransition">@transition/move</item>
+        <item name="windowSharedElementExitTransition">@transition/move</item>
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.Material.Light.Dialog</item>
@@ -622,17 +630,22 @@
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
         <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
-        <item name="preferenceFragmentPaddingSide">0dip</item>
         <item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
         <item name="preferenceStyle">@style/Preference.Material</item>
         <item name="preferenceInformationStyle">@style/Preference.Material.Information</item>
         <item name="checkBoxPreferenceStyle">@style/Preference.Material.CheckBoxPreference</item>
         <item name="switchPreferenceStyle">@style/Preference.Material.SwitchPreference</item>
+        <item name="seekBarPreferenceStyle">@style/Preference.Material.SeekBarPreference</item>
         <item name="yesNoPreferenceStyle">@style/Preference.Material.DialogPreference.YesNoPreference</item>
         <item name="dialogPreferenceStyle">@style/Preference.Material.DialogPreference</item>
         <item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
         <item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
         <item name="preferenceLayoutChild">@layout/preference_child_material</item>
+        <item name="preferencePanelStyle">@style/PreferencePanel.Material</item>
+        <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel.Material</item>
+        <item name="preferenceListStyle">@style/PreferenceHeaderList.Material</item>
+        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
+        <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
         <item name="detailsElementBackground">?attr/colorBackground</item>
 
         <!-- PreferenceFrameLayout attributes -->
@@ -1006,7 +1019,7 @@
     <style name="Theme.Material.Dialog">
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
-        <item name="windowBackground">@drawable/dialog_background_material</item>
+        <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
         <item name="windowIsFloating">true</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
@@ -1102,18 +1115,15 @@
     <!-- Theme for a window that will be displayed either full-screen on
          smaller screens (small, normal) or as a dialog on larger screens
          (large, xlarge). -->
-    <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material">
-    </style>
+    <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material" />
 
     <!-- Theme for a window without a title bar that will be displayed either
          full-screen on smaller screens (small, normal) or as a dialog on larger screens
          (large, xlarge). -->
-    <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.NoActionBar">
-    </style>
+    <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.NoActionBar" />
 
     <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.Dialog.Presentation" parent="@style/Theme.Material.NoActionBar.Fullscreen">
-    </style>
+    <style name="Theme.Material.Dialog.Presentation" parent="@style/Theme.Material.NoActionBar.Fullscreen" />
 
     <!-- Light material dialog themes -->
 
@@ -1125,7 +1135,7 @@
     <style name="Theme.Material.Light.Dialog">
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
-        <item name="windowBackground">?attr/colorBackground</item>
+        <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
         <item name="windowIsFloating">true</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
@@ -1189,15 +1199,12 @@
     <!-- Theme for a window that will be displayed either full-screen on
          smaller screens (small, normal) or as a dialog on larger screens
          (large, xlarge). -->
-    <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light">
-    </style>
+    <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light" />
 
     <!-- Theme for a window without an action bar that will be displayed either full-screen
          on smaller screens (small, normal) or as a dialog on larger screens
          (large, xlarge). -->
-    <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar"
-            parent="@style/Theme.Material.Light.NoActionBar">
-    </style>
+    <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.NoActionBar" />
 
     <!-- Material light theme for alert dialog windows, which is used by the
          {@link android.app.AlertDialog} class.  This is basically a dialog
@@ -1219,8 +1226,7 @@
     </style>
 
     <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" >
-    </style>
+    <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
 
     <!-- Default material (dark) for windows that want to have the user's selected
          wallpaper appear behind them.  -->
@@ -1236,4 +1242,11 @@
         <item name="windowNoTitle">true</item>
     </style>
 
+    <!-- Default theme for Settings and activities launched from Settings. -->
+    <style name="Theme.Material.Settings" parent="@style/Theme.Material.Light.DarkActionBar">
+        <item name="colorPrimary">@color/material_blue_grey_900</item>
+        <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+        <item name="colorAccent">@color/material_dark_teal_A400</item>
+    </style>
+
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 07a6a10..7251e7c 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageParser.PackageParserException;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.net.Uri;
@@ -60,7 +61,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -303,14 +303,13 @@
         return Uri.fromFile(outFile);
     }
 
-    private PackageParser.Package parsePackage(Uri packageURI) {
+    private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
         final String archiveFilePath = packageURI.getPath();
         PackageParser packageParser = new PackageParser(archiveFilePath);
         File sourceFile = new File(archiveFilePath);
         DisplayMetrics metrics = new DisplayMetrics();
         metrics.setToDefaults();
-        PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath,
-                metrics, 0);
+        PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics, 0);
         packageParser = null;
         return pkg;
     }
@@ -579,18 +578,18 @@
 
         PackageParser.Package pkg;
 
-        InstallParams(String outFileName, int rawResId) {
+        InstallParams(String outFileName, int rawResId) throws PackageParserException {
             this.pkg = getParsedPackage(outFileName, rawResId);
-            this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
+            this.packageURI = Uri.fromFile(new File(pkg.codePath));
         }
 
         InstallParams(PackageParser.Package pkg) {
-            this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
+            this.packageURI = Uri.fromFile(new File(pkg.codePath));
             this.pkg = pkg;
         }
 
         long getApkSize() {
-            File file = new File(pkg.mScanPath);
+            File file = new File(pkg.codePath);
             return file.length();
         }
     }
@@ -691,7 +690,8 @@
         }
     }
 
-    private PackageParser.Package getParsedPackage(String outFileName, int rawResId) {
+    private PackageParser.Package getParsedPackage(String outFileName, int rawResId)
+            throws PackageParserException {
         PackageManager pm = mContext.getPackageManager();
         File filesDir = mContext.getFilesDir();
         File outFile = new File(filesDir, outFileName);
@@ -1343,7 +1343,7 @@
                 assertUninstalled(info);
             }
         } finally {
-            File outFile = new File(ip.pkg.mScanPath);
+            File outFile = new File(ip.pkg.codePath);
             if (outFile != null && outFile.exists()) {
                 outFile.delete();
             }
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
new file mode 100644
index 0000000..cf278fb
--- /dev/null
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.IpPrefix;
+import android.os.Parcel;
+import static android.test.MoreAsserts.assertNotEqual;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.junit.Assert.assertArrayEquals;
+import java.net.InetAddress;
+import java.util.Random;
+import junit.framework.TestCase;
+
+
+public class IpPrefixTest extends TestCase {
+
+    // Explicitly cast everything to byte because "error: possible loss of precision".
+    private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
+    private static final byte[] IPV6_BYTES = {
+        (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
+        (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
+        (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
+    };
+
+    @SmallTest
+    public void testConstructor() {
+        IpPrefix p;
+        try {
+            p = new IpPrefix((byte[]) null, 9);
+            fail("Expected NullPointerException: null byte array");
+        } catch(RuntimeException expected) {}
+
+        try {
+            p = new IpPrefix((InetAddress) null, 10);
+            fail("Expected NullPointerException: null InetAddress");
+        } catch(RuntimeException expected) {}
+
+        try {
+            p = new IpPrefix((String) null);
+            fail("Expected NullPointerException: null String");
+        } catch(RuntimeException expected) {}
+
+
+        try {
+            byte[] b2 = {1, 2, 3, 4, 5};
+            p = new IpPrefix(b2, 29);
+            fail("Expected IllegalArgumentException: invalid array length");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("1.2.3.4");
+            fail("Expected IllegalArgumentException: no prefix length");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("1.2.3.4/");
+            fail("Expected IllegalArgumentException: empty prefix length");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("foo/32");
+            fail("Expected IllegalArgumentException: invalid address");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("1/32");
+            fail("Expected IllegalArgumentException: deprecated IPv4 format");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("1.2.3.256/32");
+            fail("Expected IllegalArgumentException: invalid IPv4 address");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("foo/32");
+            fail("Expected IllegalArgumentException: non-address");
+        } catch(IllegalArgumentException expected) {}
+
+        try {
+            p = new IpPrefix("f00:::/32");
+            fail("Expected IllegalArgumentException: invalid IPv6 address");
+        } catch(IllegalArgumentException expected) {}
+    }
+
+    public void testTruncation() {
+        IpPrefix p;
+
+        p = new IpPrefix(IPV4_BYTES, 32);
+        assertEquals("192.0.2.4/32", p.toString());
+
+        p = new IpPrefix(IPV4_BYTES, 29);
+        assertEquals("192.0.2.0/29", p.toString());
+
+        p = new IpPrefix(IPV4_BYTES, 8);
+        assertEquals("192.0.0.0/8", p.toString());
+
+        p = new IpPrefix(IPV4_BYTES, 0);
+        assertEquals("0.0.0.0/0", p.toString());
+
+        try {
+            p = new IpPrefix(IPV4_BYTES, 33);
+            fail("Expected IllegalArgumentException: invalid prefix length");
+        } catch(RuntimeException expected) {}
+
+        try {
+            p = new IpPrefix(IPV4_BYTES, 128);
+            fail("Expected IllegalArgumentException: invalid prefix length");
+        } catch(RuntimeException expected) {}
+
+        try {
+            p = new IpPrefix(IPV4_BYTES, -1);
+            fail("Expected IllegalArgumentException: negative prefix length");
+        } catch(RuntimeException expected) {}
+
+        p = new IpPrefix(IPV6_BYTES, 128);
+        assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
+
+        p = new IpPrefix(IPV6_BYTES, 122);
+        assertEquals("2001:db8:dead:beef:f00::80/122", p.toString());
+
+        p = new IpPrefix(IPV6_BYTES, 64);
+        assertEquals("2001:db8:dead:beef::/64", p.toString());
+
+        p = new IpPrefix(IPV6_BYTES, 3);
+        assertEquals("2000::/3", p.toString());
+
+        p = new IpPrefix(IPV6_BYTES, 0);
+        assertEquals("::/0", p.toString());
+
+        try {
+            p = new IpPrefix(IPV6_BYTES, -1);
+            fail("Expected IllegalArgumentException: negative prefix length");
+        } catch(RuntimeException expected) {}
+
+        try {
+            p = new IpPrefix(IPV6_BYTES, 129);
+            fail("Expected IllegalArgumentException: negative prefix length");
+        } catch(RuntimeException expected) {}
+
+    }
+
+    private void assertAreEqual(Object o1, Object o2) {
+        assertTrue(o1.equals(o2));
+        assertTrue(o2.equals(o1));
+    }
+
+    private void assertAreNotEqual(Object o1, Object o2) {
+        assertFalse(o1.equals(o2));
+        assertFalse(o2.equals(o1));
+    }
+
+    @SmallTest
+    public void testEquals() {
+        IpPrefix p1, p2;
+
+        p1 = new IpPrefix("192.0.2.251/23");
+        p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
+        assertAreEqual(p1, p2);
+
+        p1 = new IpPrefix("192.0.2.5/23");
+        assertAreEqual(p1, p2);
+
+        p1 = new IpPrefix("192.0.2.5/24");
+        assertAreNotEqual(p1, p2);
+
+        p1 = new IpPrefix("192.0.4.5/23");
+        assertAreNotEqual(p1, p2);
+
+
+        p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
+        p2 = new IpPrefix(IPV6_BYTES, 122);
+        assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
+        assertAreEqual(p1, p2);
+
+        p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
+        assertAreEqual(p1, p2);
+
+        p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
+        assertAreNotEqual(p1, p2);
+
+        p1 = new IpPrefix("2001:db8:dead:beef::/122");
+        assertAreNotEqual(p1, p2);
+
+        // 192.0.2.4/32 != c000:0204::/32.
+        byte[] ipv6bytes = new byte[16];
+        System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
+        p1 = new IpPrefix(ipv6bytes, 32);
+        assertAreEqual(p1, new IpPrefix("c000:0204::/32"));
+
+        p2 = new IpPrefix(IPV4_BYTES, 32);
+        assertAreNotEqual(p1, p2);
+    }
+
+    @SmallTest
+    public void testHashCode() {
+        IpPrefix p;
+        int oldCode = -1;
+        Random random = new Random();
+        for (int i = 0; i < 100; i++) {
+            if (random.nextBoolean()) {
+                // IPv4.
+                byte[] b = new byte[4];
+                random.nextBytes(b);
+                p = new IpPrefix(b, random.nextInt(33));
+                assertNotEqual(oldCode, p.hashCode());
+                oldCode = p.hashCode();
+            } else {
+                // IPv6.
+                byte[] b = new byte[16];
+                random.nextBytes(b);
+                p = new IpPrefix(b, random.nextInt(129));
+                assertNotEqual(oldCode, p.hashCode());
+                oldCode = p.hashCode();
+            }
+        }
+    }
+
+    @SmallTest
+    public void testMappedAddressesAreBroken() {
+        // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
+        // we are unable to comprehend that.
+        byte[] ipv6bytes = {
+            (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+            (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+            (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff,
+            (byte) 192, (byte) 0, (byte) 2, (byte) 0};
+        IpPrefix p = new IpPrefix(ipv6bytes, 120);
+        assertEquals(16, p.getRawAddress().length);       // Fine.
+        assertArrayEquals(ipv6bytes, p.getRawAddress());  // Fine.
+
+        // Broken.
+        assertEquals("192.0.2.0/120", p.toString());
+        assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
+    }
+
+    public IpPrefix passThroughParcel(IpPrefix p) {
+        Parcel parcel = Parcel.obtain();
+        IpPrefix p2 = null;
+        try {
+            p.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            p2 = IpPrefix.CREATOR.createFromParcel(parcel);
+        } finally {
+            parcel.recycle();
+        }
+        assertNotNull(p2);
+        return p2;
+    }
+
+    public void assertParcelingIsLossless(IpPrefix p) {
+      IpPrefix p2 = passThroughParcel(p);
+      assertEquals(p, p2);
+    }
+
+    public void testParceling() {
+        IpPrefix p;
+
+        p = new IpPrefix("2001:4860:db8::/64");
+        assertParcelingIsLossless(p);
+
+        p = new IpPrefix("192.0.2.0/25");
+        assertParcelingIsLossless(p);
+    }
+}
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java
index 814ecdd..7bc3974 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/core/tests/coretests/src/android/net/LinkAddressTest.java
@@ -30,6 +30,7 @@
 import android.net.LinkAddress;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
+import static android.test.MoreAsserts.assertNotEqual;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import static android.system.OsConstants.IFA_F_DEPRECATED;
@@ -50,6 +51,17 @@
     private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
     private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
 
+    public void testConstants() {
+        // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
+        assertNotEqual(0, RT_SCOPE_HOST);
+        assertNotEqual(0, RT_SCOPE_LINK);
+        assertNotEqual(0, RT_SCOPE_SITE);
+
+        assertNotEqual(0, IFA_F_DEPRECATED);
+        assertNotEqual(0, IFA_F_PERMANENT);
+        assertNotEqual(0, IFA_F_TENTATIVE);
+    }
+
     public void testConstructors() throws SocketException {
         LinkAddress address;
 
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 01283a6..af6a32b 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -19,7 +19,7 @@
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 
-import android.net.LinkAddress;
+import android.net.IpPrefix;
 import android.net.RouteInfo;
 import android.os.Parcel;
 
@@ -32,9 +32,8 @@
         return InetAddress.parseNumericAddress(addr);
     }
 
-    private LinkAddress Prefix(String prefix) {
-        String[] parts = prefix.split("/");
-        return new LinkAddress(Address(parts[0]), Integer.parseInt(parts[1]));
+    private IpPrefix Prefix(String prefix) {
+        return new IpPrefix(prefix);
     }
 
     @SmallTest
@@ -43,17 +42,17 @@
 
         // Invalid input.
         try {
-            r = new RouteInfo((LinkAddress) null, null, "rmnet0");
+            r = new RouteInfo((IpPrefix) null, null, "rmnet0");
             fail("Expected RuntimeException:  destination and gateway null");
         } catch(RuntimeException e) {}
 
         // Null destination is default route.
-        r = new RouteInfo((LinkAddress) null, Address("2001:db8::1"), null);
+        r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
         assertEquals(Prefix("::/0"), r.getDestination());
         assertEquals(Address("2001:db8::1"), r.getGateway());
         assertNull(r.getInterface());
 
-        r = new RouteInfo((LinkAddress) null, Address("192.0.2.1"), "wlan0");
+        r = new RouteInfo((IpPrefix) null, Address("192.0.2.1"), "wlan0");
         assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
         assertEquals(Address("192.0.2.1"), r.getGateway());
         assertEquals("wlan0", r.getInterface());
@@ -71,17 +70,19 @@
     }
 
     public void testMatches() {
-        class PatchedRouteInfo extends RouteInfo {
-            public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
-                super(destination, gateway, iface);
+        class PatchedRouteInfo {
+            private final RouteInfo mRouteInfo;
+
+            public PatchedRouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+                mRouteInfo = new RouteInfo(destination, gateway, iface);
             }
 
             public boolean matches(InetAddress destination) {
-                return super.matches(destination);
+                return mRouteInfo.matches(destination);
             }
         }
 
-        RouteInfo r;
+        PatchedRouteInfo r;
 
         r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
         assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
@@ -96,11 +97,11 @@
         assertFalse(r.matches(Address("192.0.0.21")));
         assertFalse(r.matches(Address("8.8.8.8")));
 
-        RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
+        PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
         assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
         assertFalse(ipv6Default.matches(Address("192.0.2.1")));
 
-        RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
+        PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
         assertTrue(ipv4Default.matches(Address("255.255.255.255")));
         assertTrue(ipv4Default.matches(Address("192.0.2.1")));
         assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
index 7d72f3e..d850c7c 100644
--- a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -21,7 +21,7 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
+import android.view.inputmethod.CursorAnchorInfo.Builder;
 
 public class CursorAnchorInfoTest extends InstrumentationTestCase {
     // null represents a character that is invisible, for example because it's overlapped by some
@@ -64,7 +64,7 @@
         Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
         TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
 
-        final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+        final Builder builder = new Builder();
         builder.setSelectionRange(SELECTION_START, SELECTION_END)
                 .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
                 .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
@@ -148,7 +148,7 @@
         final Matrix MATRIX3 = new Matrix();
         MATRIX3.setTranslate(210.0f, 220.0f);
         final Matrix matrix = new Matrix();
-        final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+        final Builder builder = new Builder();
 
         matrix.set(MATRIX1);
         builder.setMatrix(matrix);
@@ -171,7 +171,7 @@
     public void testBuilderAdd() throws Exception {
         // A negative index should be rejected.
         try {
-            new CursorAnchorInfoBuilder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
+            new Builder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
         } catch (IllegalArgumentException ex) {
             assertTrue(true);
         }
@@ -191,4 +191,3 @@
         }
     }
 }
-
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
index 58b7db9..42de9ea 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -36,8 +36,7 @@
         }
     }
 
-    private void setLocale(String code) {
-        Locale locale = new Locale(code);
+    private void setLocale(Locale locale) {
         Locale.setDefault(locale);
         Configuration config = new Configuration();
         config.locale = locale;
@@ -268,193 +267,193 @@
      */
     public void testMatrix100000() throws Throwable {
         final int resId = R.integer.matrix_100000;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 100);
     }
 
     public void testMatrix100001() throws Throwable {
         final int resId = R.integer.matrix_100001;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 600);
     }
 
     public void testMatrix100010() throws Throwable {
         final int resId = R.integer.matrix_100010;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 500);
     }
 
     public void testMatrix100011() throws Throwable {
         final int resId = R.integer.matrix_100011;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 100, 600);
     }
 
     public void testMatrix100100() throws Throwable {
         final int resId = R.integer.matrix_100100;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
     public void testMatrix100101() throws Throwable {
         final int resId = R.integer.matrix_100101;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
     public void testMatrix100110() throws Throwable {
         final int resId = R.integer.matrix_100110;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
     public void testMatrix100111() throws Throwable {
         final int resId = R.integer.matrix_100111;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
     public void testMatrix101000() throws Throwable {
         final int resId = R.integer.matrix_101000;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 300);
     }
 
     public void testMatrix101001() throws Throwable {
         final int resId = R.integer.matrix_101001;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 600);
     }
 
     public void testMatrix101010() throws Throwable {
         final int resId = R.integer.matrix_101010;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 500);
     }
 
     public void testMatrix101011() throws Throwable {
         final int resId = R.integer.matrix_101011;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 300, 600);
     }
 
     public void testMatrix101100() throws Throwable {
         final int resId = R.integer.matrix_101100;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
     public void testMatrix101101() throws Throwable {
         final int resId = R.integer.matrix_101101;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
     public void testMatrix101110() throws Throwable {
         final int resId = R.integer.matrix_101110;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 400);
     }
 
     public void testMatrix101111() throws Throwable {
         final int resId = R.integer.matrix_101111;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 100, 400, 600);
     }
 
     public void testMatrix110000() throws Throwable {
         final int resId = R.integer.matrix_110000;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
     public void testMatrix110001() throws Throwable {
         final int resId = R.integer.matrix_110001;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
     public void testMatrix110010() throws Throwable {
         final int resId = R.integer.matrix_110010;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
     public void testMatrix110011() throws Throwable {
         final int resId = R.integer.matrix_110011;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
     public void testMatrix110100() throws Throwable {
         final int resId = R.integer.matrix_110100;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
     public void testMatrix110101() throws Throwable {
         final int resId = R.integer.matrix_110101;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 
     public void testMatrix110110() throws Throwable {
         final int resId = R.integer.matrix_110110;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
     public void testMatrix110111() throws Throwable {
         final int resId = R.integer.matrix_110111;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 
     public void testMatrix111000() throws Throwable {
         final int resId = R.integer.matrix_111000;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
     public void testMatrix111001() throws Throwable {
         final int resId = R.integer.matrix_111001;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
     public void testMatrix111010() throws Throwable {
         final int resId = R.integer.matrix_111010;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 200);
     }
 
     public void testMatrix111011() throws Throwable {
         final int resId = R.integer.matrix_111011;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 200, 600);
     }
 
     public void testMatrix111100() throws Throwable {
         final int resId = R.integer.matrix_111100;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
     public void testMatrix111101() throws Throwable {
         final int resId = R.integer.matrix_111101;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 
     public void testMatrix111110() throws Throwable {
         final int resId = R.integer.matrix_111110;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 400);
     }
 
     public void testMatrix111111() throws Throwable {
         final int resId = R.integer.matrix_111111;
-        setLocale("sv_SE");
+        setLocale(new Locale("sv", "SE"));
         assertResource(resId, 200, 400, 600);
     }
 }
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index c6bccfe..6437e07 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -42,12 +42,21 @@
 $(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf))
 $(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf))
 
+extra_font_files := \
+    DroidSans.ttf \
+    DroidSans-Bold.ttf
+
 ################################
 # On space-constrained devices, we include a subset of fonts:
 ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+
 droidsans_fallback_src := DroidSansFallback.ttf
-extra_font_files := DroidSans.ttf DroidSans-Bold.ttf
-else
+
+else  # !SMALLER_FONT_FOOTPRINT
+
+droidsans_fallback_src := DroidSansFallbackFull.ttf
+
+ifneq ($(EXTENDED_FONT_FOOTPRINT),true)
 include $(CLEAR_VARS)
 LOCAL_MODULE := MTLmr3m.ttf
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
@@ -55,12 +64,9 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
 include $(BUILD_PREBUILT)
+extra_font_files += MTLmr3m.ttf
+endif  # !EXTENDED_FONT_FOOTPRINT
 
-droidsans_fallback_src := DroidSansFallbackFull.ttf
-extra_font_files := \
-	DroidSans.ttf \
-	DroidSans-Bold.ttf \
-	MTLmr3m.ttf
 endif  # SMALLER_FONT_FOOTPRINT
 
 ################################
@@ -106,6 +112,7 @@
 ifeq ($(MINIMAL_FONT_FOOTPRINT),true)
 
 $(eval $(call create-font-symlink,Roboto-Black.ttf,Roboto-Bold.ttf))
+$(eval $(call create-font-symlink,Roboto-BlackItalic.ttf,Roboto-BoldItalic.ttf))
 $(eval $(call create-font-symlink,Roboto-Light.ttf,Roboto-Regular.ttf))
 $(eval $(call create-font-symlink,Roboto-LightItalic.ttf,Roboto-Italic.ttf))
 $(eval $(call create-font-symlink,Roboto-Medium.ttf,Roboto-Regular.ttf))
@@ -120,6 +127,7 @@
 else # !MINIMAL_FONT
 font_src_files += \
     Roboto-Black.ttf \
+    Roboto-BlackItalic.ttf \
     Roboto-Light.ttf \
     Roboto-LightItalic.ttf \
     Roboto-Medium.ttf \
diff --git a/data/fonts/Roboto-BlackItalic.ttf b/data/fonts/Roboto-BlackItalic.ttf
new file mode 100644
index 0000000..3ebdc7d
--- /dev/null
+++ b/data/fonts/Roboto-BlackItalic.ttf
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index c2d5afe..1eaae65 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -219,6 +219,26 @@
     </family>
     <family>
         <fileset>
+            <file lang="zh-CN">NotoSansHans-Regular.otf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file lang="zh-TW">NotoSansHant-Regular.otf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file lang="ja">NotoSansJP-Regular.otf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file lang="ko">NotoSansKR-Regular.otf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NanumGothic.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index e5573bb..70fc6a2 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -25,6 +25,7 @@
     Roboto-Italic.ttf \
     Roboto-BoldItalic.ttf \
     Roboto-Black.ttf \
+    Roboto-BlackItalic.ttf \
     Roboto-Light.ttf \
     Roboto-LightItalic.ttf \
     Roboto-Medium.ttf \
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
index 646b33b..8c59fea 100644
--- a/data/fonts/system_fonts.xml
+++ b/data/fonts/system_fonts.xml
@@ -82,6 +82,7 @@
         </nameset>
         <fileset>
             <file>Roboto-Black.ttf</file>
+            <file>Roboto-BlackItalic.ttf</file>
         </fileset>
     </family>
 
diff --git a/docs/html/auto/images/carlogos.png b/docs/html/auto/images/carlogos.png
new file mode 100644
index 0000000..3522aa3
--- /dev/null
+++ b/docs/html/auto/images/carlogos.png
Binary files differ
diff --git a/docs/html/auto/images/figure01.png b/docs/html/auto/images/figure01.png
new file mode 100644
index 0000000..3044020
--- /dev/null
+++ b/docs/html/auto/images/figure01.png
Binary files differ
diff --git a/docs/html/auto/images/figure02.png b/docs/html/auto/images/figure02.png
new file mode 100644
index 0000000..1b87224
--- /dev/null
+++ b/docs/html/auto/images/figure02.png
Binary files differ
diff --git a/docs/html/auto/images/figure03.png b/docs/html/auto/images/figure03.png
new file mode 100644
index 0000000..0c4e20d
--- /dev/null
+++ b/docs/html/auto/images/figure03.png
Binary files differ
diff --git a/docs/html/auto/images/figure04.png b/docs/html/auto/images/figure04.png
new file mode 100644
index 0000000..3e9c894
--- /dev/null
+++ b/docs/html/auto/images/figure04.png
Binary files differ
diff --git a/docs/html/auto/images/figure05.png b/docs/html/auto/images/figure05.png
new file mode 100644
index 0000000..9c1d9b8
--- /dev/null
+++ b/docs/html/auto/images/figure05.png
Binary files differ
diff --git a/docs/html/auto/images/figure06.png b/docs/html/auto/images/figure06.png
new file mode 100644
index 0000000..8140f0c
--- /dev/null
+++ b/docs/html/auto/images/figure06.png
Binary files differ
diff --git a/docs/html/auto/images/figure07.png b/docs/html/auto/images/figure07.png
new file mode 100644
index 0000000..82c1c76
--- /dev/null
+++ b/docs/html/auto/images/figure07.png
Binary files differ
diff --git a/docs/html/auto/images/figure08.png b/docs/html/auto/images/figure08.png
new file mode 100644
index 0000000..f11e3a8
--- /dev/null
+++ b/docs/html/auto/images/figure08.png
Binary files differ
diff --git a/docs/html/auto/images/hero.jpg b/docs/html/auto/images/hero.jpg
new file mode 100644
index 0000000..3f9114f
--- /dev/null
+++ b/docs/html/auto/images/hero.jpg
Binary files differ
diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
new file mode 100644
index 0000000..c7a3a4e
--- /dev/null
+++ b/docs/html/auto/index.jd
@@ -0,0 +1,223 @@
+page.title=Android Auto
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.type=about
+
+@jd:body
+
+<style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+  display:none;
+}
+</style>
+
+<style>
+#footer {
+  display: none;
+}
+.content-footer {
+  display: none;
+}
+#hero-height {
+  height:calc(100% - 100px);
+}
+</style>
+
+
+<div class="landing-body-content">
+  <div class="landing-hero-container">
+
+    <div id="hero-height" class="landing-section auto-hero">
+      <div class="landing-hero-scrim"></div>
+      <div class="landing-hero-wrap">
+        <div class="vertical-center-outer">
+          <div class="vertical-center-inner">
+
+            <div class="col-10">
+              <div class="landing-section-header">
+                <div class="landing-h1 hero">Android Auto</div>
+                <div class="landing-subhead hero">Entertainment and services on your dashboard</div>
+                <div class="landing-hero-description">
+                  <p>Display and control your handheld app in vehicles.
+                  Build apps with easy-to-use UI templates that
+                  let users keep their eyes on the road.</p>
+                </div>
+
+              <div class="landing-body">
+                <a href="{@docRoot}auto/overview.html" class="landing-button landing-primary" style="margin-top: 40px;">
+                  Developer Overview
+                </a>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div> <!-- end .wrap -->
+
+      <div class="landing-scroll-down-affordance">
+        <a class="landing-down-arrow" href="#android-in-car">
+          <img src="{@docRoot}wear/images/carrot.png" alt="Scroll down to read more">
+        </a>
+      </div>
+    </div> <!-- end .landing-section .landing-hero -->
+  </div> <!-- end .landing-hero-container -->
+
+    <div class="landing-rest-of-page">
+
+      <div class="landing-section landing-gray-background" id="android-in-car">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Bringing Android to Your Car</div>
+          </div>
+
+          <div class="landing-body">
+            <p>When users connect their Android phone to an Android Auto enabled vehicle, the
+              system shows an interface that lets users select compatible apps and services to run.
+            </p>
+            <p>Android Auto provides new APIs and tools that your existing Android apps can
+              leverage to run on any compatible vehicle. Users interact with your apps through the
+              touch screen and the physical buttons on the vehicle’s dashboard. Your apps can also
+              respond to voice commands.
+            </p>
+          </div>
+
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+
+      <div class="landing-section">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">One Platform</div>
+          </div>
+
+          <div class="landing-body">
+            <p>Android Auto is an extension of the Android platform. You can easily adapt
+            existing apps for Android Auto and reuse many of the Android APIs and services you
+            are already familiar with.</p>
+            <p>The Android Auto platform and SDK let you write your apps only once, without having
+            to worry about vehicle-specific hardware differences like screen resolution, software
+            interfaces, knobs and touch controls. Your app runs the same on any compatible
+            vehicle.</p>
+          </div>
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+      <div class="landing-section landing-gray-background" >
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Minimizing Distraction</div>
+          </div>
+
+          <div class="landing-body">
+            <p>We designed Android Auto to minimize driver distraction. Android Auto provides UI
+              templates for several app categories. These templates define the user interaction model
+              for any app and follow international best practices for reducing driver distraction.</p>
+            <p>You can customize these templates to fit your brand and link them to your app’s
+              content and functionality, instead of building new UIs and testing them for driver
+              distraction, which is a lengthy and costly process.</p>
+            <p>Android Auto locks any device that users connect to a compatible vehicle, so drivers
+              interact with the device using voice actions and the vehicle’s input controls.</p>
+          </div>
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+      <div class="landing-section landing-white-background">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Building an Ecosystem</div>
+          </div>
+          <div class="landing-body landing-align-center">
+              <p style="margin-bottom:20px">
+                Android Auto is coming soon to new cars from these manufacturers:
+              </p>
+          </div>
+          <div style="width:800px;margin:0 auto">
+            <img src="{@docRoot}auto/images/carlogos.png" alt="Partners" />
+          </div>
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+
+      <div class="landing-section" >
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Developer Stories</div>
+          </div>
+
+          <div class="landing-body">
+            <p>We're working with developers to bring many popular apps to Android Auto:</p>
+            <p>
+
+            </p>
+          </div>
+
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+
+      <div class="landing-section" style="background-color:#f5f5f5">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-pre-h1">Coming soon</div>
+            <div class="landing-h1">Android Auto SDK</div>
+            <div style="text-align:center;margin-top:20px;font-size:14pt;margin-bottom:-5px">
+                <a href="https://docs.google.com/a/google.com/forms/d/1ANgYOoYLkfyZ2JRPSU34Nep5yNaU-Ha2syXJ9b4xLrA/viewform">Sign up for updates</a>
+            </div>
+          </div>
+
+          <div class="landing-body">
+            <p>In the coming months, we’ll be releasing the Android Auto SDK, which includes APIs
+              and tools to make your existing apps compatible with Android Auto. The first version
+              of the SDK will provide templates and APIs for music, podcast, live radio, and audio
+              news apps, as well as limited voice actions.</p>
+            <p style="margin-bottom:40px">
+              Future versions of the Android Auto SDK will include support for a selection of
+              Android notifications, additional voice actions, and templates and APIs for
+              messaging, communication, local search, and more.</p>
+
+              <a target="_blank" href="http://g.co/androidautodev">
+                <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Auto Developers">
+              </a>
+              <p style="margin-bottom:5px">G+ Community</p>
+              <p class="landing-small">
+                Join the Android Auto developer community on Google+ to stay involved, get the
+                latest updates, and exchange experiences with other developers.
+                <a target="_blank" href="http://g.co/androidautodev">+Android Auto Developers</a>
+              </p>
+          </div>
+
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+    </div> <!-- end .landing-rest-of-page -->
+
+
+    <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
+      <div class="layout-content-col col-16" style="padding-top:4px">
+        <style>#___plusone_0 {float:right !important;}</style>
+        <div class="g-plusone" data-size="medium"></div>
+      </div>
+    </div>
+    <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+      <div id="copyright">
+        Except as noted, this content is
+        licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+        Creative Commons Attribution 2.5</a>. For details and
+        restrictions, see the <a href="/license.html">Content
+        License</a>.
+      </div>
+    </div>
+
+
+  </div> <!-- end landing-body-content -->
+
+  <script>
+  $("a.landing-down-arrow").on("click", function(e) {
+    $("body").animate({
+      scrollTop: $(".auto-hero").height() + 120
+    }, 1000, "easeOutQuint");
+    e.preventDefault();
+  });
+  </script>
diff --git a/docs/html/auto/overview.jd b/docs/html/auto/overview.jd
new file mode 100644
index 0000000..8748bff
--- /dev/null
+++ b/docs/html/auto/overview.jd
@@ -0,0 +1,363 @@
+fullpage=true
+page.viewport_width=970
+no_footer_links=true
+excludeFromSuggestions=true
+page.metaDescription=Android Auto
+
+@jd:body
+
+<style>
+.jd-descr {
+    height:auto;
+}
+#copyright {
+    margin-top:-35px;
+}
+</style>
+
+<div style="width:780px; margin:0 auto;">
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#design">Design</a>
+    <ol>
+      <li><a href="#designprinciples">Design Principles</a></li>
+      <li><a href="#uioverview">UI Overview</a></li>
+    </ol>
+  </li>
+  <li><a href="#architecture">Architecture</a></li>
+  <li><a href="#uitemplates">UI Templates</a>
+    <ol>
+      <li><a href="#launchapp">Launch App</a></li>
+      <li><a href="#useractions">User Actions</a></li>
+      <li><a href="#drawertransitions">Drawer Transitions</a></li>
+      <li><a href="#daynighttransitions">Day and Night Transitions</a></li>
+      <li><a href="#customizetemplates">Customizing Templates</a></li>
+    </ol>
+  </li>
+  <li><a href="#devprocess">Development Process</a></li>
+  <li><a href="#emulator">Testing Your App</a></li>
+  <li><a href="#running">Running Your App</a></li>
+</ol>
+</div>
+</div>
+
+<h1>Android Auto Developer Overview</h1>
+
+<p>Android Auto extends the Android platform to car entertainment systems. When users connect
+their Android handheld device to a compatible vehicle, Android Auto lets users project apps on
+the vehicle’s touchscreen and interact with them using the vehicle’s controls.</p>
+
+<dl>
+<dt style="margin-bottom:10px"><strong>UI Templates</strong></dt>
+<dd style="margin-bottom:20px">
+Android Auto defines interaction models and UI templates for several app categories. The
+first version of Android Auto supports media apps, such as music, podcast, live radio, and
+audio news apps. Future versions will support messaging, communication, local search apps,
+and more.
+</dd>
+<dt style="margin-bottom:10px"><strong>Notifications</strong></dt>
+<dd style="margin-bottom:20px">
+The platform will integrate with existing Android APIs for notifications. Users will get
+some notifications from Android apps on the vehicle’s screen.</dd>
+
+<dt style="margin-bottom:10px"><strong>Voice Actions</strong></dt>
+<dd style="margin-bottom:20px">
+Android Auto supports voice search and voice actions for media apps. Future versions
+will support additional voice actions.</dd>
+
+<dt style="margin-bottom:10px"><strong>Easy Development Workflow</strong></dt>
+<dd style="margin-bottom:20px">
+To extend an existing Android app for Android Auto, you implement a set of interfaces and
+services defined in the platform. You can reuse existing functionality and many Android APIs
+you already know.</dd>
+</dl>
+
+<p>We’ll release the Android Auto SDK in the coming months, which will let you test your
+Android Auto experience on a regular Android device.</p>
+
+
+<h2 id="design" style="margin-top:30px">Design</h2>
+
+<p>Digital experiences for cars should complement and augment driving, not demand the driver's
+attention. Designing these experiences for cars is fundamentally different than in the case of
+phones and tablets. It requires rethinking how these experiences unfold.</p>
+
+<h3 id="designprinciples" style="margin-top:25px">Design Principles</h3>
+
+<p><strong>Glanceable</strong>. We designed Android Auto to reduce UI complexity, optimize user
+interactions, and lower cognitive load. Effective apps show just enough information
+and only provide features that do not require excessive menu interaction and navigation.</p>
+
+<p><strong>Predictive, yet predictable</strong>. Android Auto leverages rich, contextual awareness
+to keep the driver informed about important situations. Timely help is combined with predictable
+functions. Effective apps use patterns for common tasks and show timely information only when
+relevant.</p>
+
+<p><strong>Connected</strong>. Android Auto works with apps that drivers already use in other
+devices. Android Auto promotes a continuous app experience from phones and tablets to cars,
+providing access to user's existing settings, subscriptions, and digital libraries. Experiences
+that bring personal content and context from other devices are part of Android Auto.</p>
+
+<p><strong>Integrated</strong>. Android Auto blends your apps with the vehicle's entertainment
+system, creating a truly integrated experience in every car. By using the vehicle's screen and
+controls, apps feel tailored to each car.</p>
+
+<h3 id="uioverview" style="margin-top:25px">UI Overview</h3>
+
+<p>Android Auto is a new environment that leverages existing UI models where appropiate and adds
+new models based on constrains and context. There are three primary concepts for Android Auto:
+<strong>Suggest</strong>, a unified place for predictive content; <strong>Demand</strong>, a
+pervasive way to interact with voice; and the <strong>Facets</strong>, organized spaces for
+primary activities, apps and content.</p>
+
+<dl>
+<dt style="margin-bottom:10px"><strong>Suggest: The Google Facet</strong></dt>
+<dd style="margin-bottom:20px">
+Core of continuity and extensibility is contextual stream of Now-like cards, powered by your
+apps and notifications. Relevant, timely, and dynamic, the stream organizes likely people, media,
+places, and information so drivers can quickly continue their activities or start something new.
+Google Now and notifications enable drivers to use the apps and services they know when they are
+most relevant.
+</dd>
+<dt style="margin-bottom:10px"><strong>Demand: The Voice Layer</strong></dt>
+<dd style="margin-bottom:20px">
+Voice-enabled tasks lets drivers accomplish their goals without taking their eyes off the road.
+Android Auto defines actions and intents that your app can register for.
+These are accessible through both persistent UI elements and dedicated hardware controls.
+</dd>
+<dt style="margin-bottom:10px"><strong>Facets and Templates: App-powered activities</strong></dt>
+<dd style="margin-bottom:20px">
+In the car, pages of app icons and different UIs create a distracting and dangerous situation.
+Instead, Android Auto apps power templates which help provide simple but customizable UIs
+for common interactions such as media or communications. Templates incorporate common behaviors,
+such as play/pause or reply to a message, while still letting your app promote its value
+and its brand. Apps are organized into facets (or activities) to enable quick access.
+</dd>
+</dl>
+
+<p>Android Auto uses the input and output mechanisms in each vehicle to tailor the interactions.
+Some vehicles have dedicated hardware controls, while others have primarily touch-based systems.
+Android Auto maps common actions and intents across these diverse sets of controls and outputs to
+enable you to concentrate on your unique app experience.</p>
+
+
+<h2 id="architecture" style="margin-top:30px">Architecture</h2>
+
+<p>The Android Auto app projects your app's customized UI on the vehicle's screen. To communicate
+with the Android Auto app, your media app implements a set of media interfaces.</p>
+
+<div style="width:750px;margin:0 auto">
+<img src="/auto/images/figure01.png" alt="" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1</strong> - Architecture of Android Auto.
+</p>
+</div>
+
+<p>The architecture consists of the following components:</p>
+
+<p><strong>Media App</strong> - Runs a media service that exposes content through browsing and
+playback APIs. The service provides content to the Android Auto app. This is your Android app.</p>
+
+<p><strong>Android Auto App</strong> - Creates a templated UI and handles user interactions.
+This app uses a media client to request content from the media service running in the media
+app. The client requests data from the media service and monitors service states.</p>
+
+<p><strong>Vehicle Display</strong> - Shows app content and supports user interaction via
+on-screen soft buttons and other components, such as physical buttons or steering
+wheel controls.</p>
+
+<p>Android media apps must implement binders to these APIs:</p>
+
+<ul>
+<li><strong>Browsing</strong> - Enables a media client to browse a hierarchy of a user’s
+media collection, presented as a virtual file system with containers (similar to directories)
+and items (similar to files).</li>
+<li><strong>Playback</strong> - Enables a media client to control media playback and monitor
+playback state through callbacks.</li>
+</ul>
+
+
+<h2 id="uitemplates" style="margin-top:30px">UI Templates</h2>
+
+<p>The Android Auto app uses a templated UI to display content and user interaction
+opportunities. Android Auto provides you with a set of standard UI templates that follow
+international guidelines for minimizing driving distraction. You do not have to test your
+app's UI for for driver distraction, which is a lengthy and expensive process involving
+multiple legislations across the globe and different standards for each vehicle OEM.</p>
+
+<p>The UI templates define interfaces for browsing, searching, and listening to content from
+media apps. Although you cannot change the standard template format or layout, you can customize
+the template colors, action icons, background images, and more.</p>
+
+<h3 id="launchapp" style="margin-top:25px">Launch App Template</h3>
+
+<p>The Launcher template shows all the compatible media apps installed on the user’s
+Android device and lets users select one of them from an scrollable list:</p>
+
+<div style="width:500px;margin:0 auto">
+<img src="/auto/images/figure02.png" alt="" id="figure2" />
+<p class="img-caption">
+  <strong>Figure 2.</strong> The Launcher template.
+</p>
+</div>
+
+<h3 style="margin-top:25px">Primary App Template</h3>
+
+<p>After the user selects a media app, the display shows the primary app template. Figure
+3 shows the elements of this template that you can customize:</p>
+
+<div style="width:428px;margin:0 auto">
+<img src="/auto/images/figure03.png" alt="" id="figure3" />
+<p class="img-caption">
+  <strong>Figure 3.</strong> The main application template.
+</p>
+</div>
+
+<p>You can customize the primary app template to show your own icons, app name, and
+background images. Figure 4 shows an example of a customized template:</p>
+
+<div style="width:787px;margin:0 auto">
+<img src="/auto/images/figure04.png" alt="" id="figure4" />
+<p class="img-caption">
+  <strong>Figure 4.</strong> A customized template.
+</p>
+</div>
+
+<h3 id="useractions" style="margin-top:25px">User Actions</h3>
+
+<p>The primary app template supports four main actions on the action bar, four auxiliary actions
+on the overflow bar, and the <em>Return</em> action. You can use standard controls and customize
+the actions and icons, as shown in Figure 5.</p>
+
+<div style="width:500px;margin:0 auto">
+<img src="/auto/images/figure05.png" alt="" id="figure5" />
+<p class="img-caption">
+  <strong>Figure 5.</strong> Custom icons for auxiliary actions.
+</p>
+</div>
+
+<h3 id="drawertransitions" style="margin-top:25px">Drawer Transitions</h3>
+
+<p>For browse actions, the display shows the drawer transition and template:</p>
+
+<div style="width:750px;margin:0 auto">
+<img src="/auto/images/figure06.png" alt="" id="figure6" />
+<p class="img-caption">
+  <strong>Figure 6.</strong> The drawer transition.
+</p>
+</div>
+
+<p>After the transition from the primary app template to the drawer template, the drawer
+appears on the center. The customized drawer template shows the media containers and
+media files provided by the media service in your app. You can also customize drawers
+with icons for list items.</p>
+
+<div style="width:500px;margin:0 auto">
+<img src="/auto/images/figure07.png" alt="" id="figure7" />
+<p class="img-caption">
+  <strong>Figure 7.</strong> A customized drawer template.
+</p>
+</div>
+
+<h3 id="daynighttransitions" style="margin-top:25px">Day and Night Transitions</h3>
+
+<p>All the templates support different color schemes for day and night, as shown in
+Figure 8. The platform provides the state (day or night) and makes adjustments automatically.</p>
+
+<div style="width:780px;margin:0 auto">
+<img src="/auto/images/figure08.png" alt="" id="figure8" />
+<p class="img-caption">
+  <strong>Figure 8.</strong> Day and night transitions.
+</p>
+</div>
+
+<h3 id="customizetemplates" style="margin-top:25px">Customizing Templates</h3>
+
+<p>To customize the templates, provide the following app-specific resources and actions
+to the Android Auto media client.</p>
+
+<ul>
+<li><strong>Resources</strong> - App logo, app name, theme colors, and background images.</li>
+<li><strong>Actions</strong> - Multiple custom actions; for example: <em>Thumbs Up/Down</em>,
+<em>Favorite</em>, and <em>Bookmark</em>. These actions are app-specific.</li>
+</ul>
+
+<p>If provided, the media client automatically uses them in the templated UI.</p>
+
+
+<h2 id="devprocess" style="margin-top:30px">Development Process</h2>
+
+<p class="note"><strong>Note:</strong> When released, the Android Auto SDK will provide
+media service interfaces, an APK for handheld devices that simulates the Android Auto
+app, and other tools for Android Auto development.</p>
+
+<p>To create a media app for Android Auto, you include an Android service in your app
+that implements the media service interfaces provided by the Android Auto SDK. These
+interfaces define functionality for browsing and finding content, playing media,
+customizing the UI template, and performing app-specific actions.</p>
+
+<p>The media service interfaces present the content library as a navigable tree and enable
+clients to play media, get album art, obtain theme resources for the UI template, and
+invoke app-specific actions.</p>
+
+<p>You don’t have to create a new app for Android Auto: you can extend your existing
+Android app with implementations of the media service interfaces. Your service exposes
+your app’s media content, theme resources, and app-specific actions using the methods and
+data types specified by the media service interfaces. This simplifies the development
+cycle because:</p>
+
+<ul>
+<li>You do not have to maintain a separate project for Android Auto</li>
+<li>You can reuse existing functionality from your Android app</li>
+</ul>
+
+<p>The Android Auto client presents the customized UI to users and invokes the
+functionality from your service as needed. This has two additional advantages:</p>
+
+<ul>
+<li>Your app does not implement a UI for Android Auto</li>
+<li>Your app does not manage user interactions directly</li>
+</ul>
+
+<p>This also means that you do not have to worry about vehicle-specific hardware
+differences such as screen resolutions, software interfaces, knobs and touch
+controls.</p>
+
+
+<h2 id="emulator" style="margin-top:30px">Testing Your App on an Android Device</h2>
+
+<p>The Android Auto SDK includes an APK with a media client implementation, which is
+similar to those available in compatible vehicles. To test your app with this
+client:</p>
+
+<ol>
+<li>Get an Android device with a similar form factor to a dashboard screen (like a
+Nexus 7).</li>
+<li>Configure the device for Android development.</li>
+<li>Install the APK for the media client from the Android Auto SDK on the device.</li>
+<li>Install the APK for your app on the device.</li>
+<li>Open the media client app from the Android Auto SDK on the device.</li>
+<li>Select your app from the list of available services.</li>
+</ol>
+
+<p>The customized UI for your app appears on the client. You can navigate the content
+library and play media. If your app provides app-specific actions, these actions appear
+in the UI controls.</p>
+
+
+<h2 id="running" style="margin-top:30px">Running Your App on Android Auto</h2>
+
+<p>Media apps are available on the Google Play Store for compatible Android devices.
+When users connect their Android device to a compatible vehicle, the
+Android Auto media client shows a list of all the Android apps installed on the phone
+that implement the media service interfaces.</p>
+
+<p>When users select one of these apps, the Android Auto media client uses the app’s
+service to respond to user input and invoke the methods in the media service interfaces
+to build the UI, navigate the content library, and play media.</p>
+
+<div style="margin-bottom:40px"> </div>
+</div>
diff --git a/docs/html/design/design_toc.cs b/docs/html/design/design_toc.cs
index 4c2aab2..2bd0bf9 100644
--- a/docs/html/design/design_toc.cs
+++ b/docs/html/design/design_toc.cs
@@ -67,6 +67,25 @@
   </li>
 
   <li class="nav-section">
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>design/devices.html">Devices</a></div>
+    <ul>
+      <!-- wear design goes here -->
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>design/tv/index.html">TV</a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>design/tv/principles.html">Design Principles</a></li>
+          <li><a href="<?cs var:toroot ?>design/tv/ui-overview.html">UI Overview</a></li>
+          <li><a href="<?cs var:toroot ?>design/tv/style.html">Style</a></li>
+          <li><a href="<?cs var:toroot ?>design/tv/patterns.html">Patterns</a></li>
+        </ul>
+      </li>
+
+    </ul>
+  </li>
+
+
+  <li class="nav-section">
     <div class="nav-section-header empty"><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></div>
   </li>
 
diff --git a/docs/html/design/tv/images/apps-games-rows.png b/docs/html/design/tv/images/apps-games-rows.png
new file mode 100644
index 0000000..1724147
--- /dev/null
+++ b/docs/html/design/tv/images/apps-games-rows.png
Binary files differ
diff --git a/docs/html/design/tv/images/atv-home.png b/docs/html/design/tv/images/atv-home.png
new file mode 100644
index 0000000..2c18827
--- /dev/null
+++ b/docs/html/design/tv/images/atv-home.png
Binary files differ
diff --git a/docs/html/design/tv/images/atv.png b/docs/html/design/tv/images/atv.png
new file mode 100644
index 0000000..cd96164
--- /dev/null
+++ b/docs/html/design/tv/images/atv.png
Binary files differ
diff --git a/docs/html/design/tv/images/overscan.png b/docs/html/design/tv/images/overscan.png
new file mode 100644
index 0000000..bf08dd8
--- /dev/null
+++ b/docs/html/design/tv/images/overscan.png
Binary files differ
diff --git a/docs/html/design/tv/images/recommendations.png b/docs/html/design/tv/images/recommendations.png
new file mode 100644
index 0000000..579b390
--- /dev/null
+++ b/docs/html/design/tv/images/recommendations.png
Binary files differ
diff --git a/docs/html/design/tv/images/search.png b/docs/html/design/tv/images/search.png
new file mode 100644
index 0000000..be0d778
--- /dev/null
+++ b/docs/html/design/tv/images/search.png
Binary files differ
diff --git a/docs/html/design/tv/images/settings.png b/docs/html/design/tv/images/settings.png
new file mode 100644
index 0000000..f9f45fa
--- /dev/null
+++ b/docs/html/design/tv/images/settings.png
Binary files differ
diff --git a/docs/html/design/tv/index.jd b/docs/html/design/tv/index.jd
new file mode 100644
index 0000000..2519e25
--- /dev/null
+++ b/docs/html/design/tv/index.jd
@@ -0,0 +1,31 @@
+page.title=Design for TV
+header.justLinks=1
+footer.hide=1
+@jd:body
+
+<style>
+#landing-graphic-container {
+  position: relative;
+}
+
+#text-overlay {
+  position: absolute;
+  left: 0;
+  top: 402px;
+  width: 220px;
+}
+</style>
+
+<div id="landing-graphic-container">
+  <div id="text-overlay">
+    <span itemprop="description">
+      Build beautiful apps for the biggest screen in the house.</span>
+    <br><br>
+    <a href="{@docRoot}design/tv/principles.html"
+       class="landing-page-link">Design Principles</a>
+  </div>
+
+  <a href="{@docRoot}design/tv/principles.html">
+    <img src="{@docRoot}design/tv/images/atv.png" style="margin-left: 70px;">
+  </a>
+</div>
diff --git a/docs/html/design/tv/patterns.jd b/docs/html/design/tv/patterns.jd
new file mode 100644
index 0000000..c8cc0b0
--- /dev/null
+++ b/docs/html/design/tv/patterns.jd
@@ -0,0 +1,100 @@
+page.title=Patterns for TV
+page.tags="design"
+@jd:body
+
+<p>As a developer of apps for TV, you should follow certain patterns to enable users to
+  quickly understand and efficiently your app. This section describes recommended design patterns
+  for TV apps.</p>
+
+<h2>Navigation</h2>
+
+<p>Users typically navigate TV devices using a directional pad (D-Pad). This type of controller
+  limits movement to up, down, left, and right. In a typical D-Pad remote, hardware keys that
+  correspond to those directions are present and an additional action key is available to make a
+  selection. As you design your Android application for TVs, pay special attention to how users
+  navigate your application when using a remote control instead of a touchscreen.</p>
+
+<p>[add visual: D-Pad image or illustration]</p>
+
+<p>A key aspect of making your application work well with a D-Pad controller is to make sure
+  that there is always a object that is obviously in focus. If a user cannot see what is in focus,
+  they will not be able to navigate your app intuitively with this type of controller.</p>
+
+<p>Optimize your app screen layouts for D-Pad navigation. Align objects in your app lists and
+  grids to make navigation within each screen intuitive. Design your layout so it takes advantage of
+  two-axis navigation.</p>
+
+
+<h2>Home and Back Buttons</h2>
+
+<p>
+  In addition to the D-Pad buttons, Android TV devices always include Home and Back buttons on their
+  controllers. Make sure the Back button functions within your app in a way that is consistent with
+  the general <a href="{@docRoot}design/patterns/navigation.html">Android Design guidelines</a>.
+</p>
+
+
+<h2>Focus and Selection</h2>
+
+<p>Providing good focus and selection indicators is key to making your app useable on TV. As
+  mentioned previously, making sure that an object is always selected in your app is critical for
+  effective navigation using a D-Pad. This requirement also means that you must use focus indicators
+  that are easy to recognize and should be consistent throughout your app.</p>
+
+<p>
+  [add visual of selected item on screen]
+</p>
+
+<p>The default focus indicator used in Android TV use a combination of scale, shadow,
+  brightness, and opacity. The focus feedback is enhanced by displaying an animation going from a
+  non-focused to a focused state and back. Instead of immediately applying the focus transformation,
+  it is animated into place to reduce abrupt changes and help users notice how the object changed.</p>
+
+<h2>Audio Feedback</h2>
+
+<p>Sounds on Android TV bring a cinematic quality to the interaction experience. You should
+  consider adding sounds for user actions or to provide feedback when a user is only partially
+  visually engaged with the screen (e.g., because they have their hands full or are multitasking).
+  You should also consider using sounds as alternatives to error messages, for example to indicate
+  that a user has reached the end of a list or is trying to navigate to an undefined location.</p>
+
+<h2>Banners</h2>
+
+<p>
+  App Banners represent your app on the home screen of TV devices and serves and as a way for
+  users to launch your app. Here are specific requirements for the banner image:
+</p>
+
+<ul>
+  <li>Size: 320 x 180 px, xhdpi resource</li>
+  <li>Text should be included in the image. If your app is available in more than one
+      language, you must provide version of the banner image for each supported language.</li>
+</ul>
+
+
+<h2>App Icons</h2>
+
+<p>The app icon is shown in recommendation cards on the Home screen, search results and the main
+  Browse screen of your app if you use {@code BrowseFragment}. Here are the specific
+  requirements for the app icon:</p>
+
+<ul>
+  <li><p>Full color: size: 52x52dp, PNG</p></li>
+  <li><p>Monocolor: size 52x52dp, white(#fff) icon with transparent background, PNG</p></li>
+</ul>
+
+
+<h2>Background Images</h2>
+
+<p>Background images are displayed in the background of your app to provide additional visual
+  interest, information or branding. The BrowseFragment and DetailsFragment classes in the Leanback
+  support library provide specific support for background images and updating them as items are
+  brought into and out of focus. Here are the specific requirements for background images:</p>
+
+<ul>
+  <li>2016x1134 (1920x1080 + 5% extra margin for motion)</li>
+</ul>
+
+<p>
+  <strong>Note:</strong> If the image does not meet this requirement, it is scaled to fit.
+</p>
\ No newline at end of file
diff --git a/docs/html/design/tv/principles.jd b/docs/html/design/tv/principles.jd
new file mode 100644
index 0000000..5c0ce10
--- /dev/null
+++ b/docs/html/design/tv/principles.jd
@@ -0,0 +1,45 @@
+page.title=Design Principles for TV
+@jd:body
+
+<p>Users bring a specific set of expectations to the experience of watching TV, versus
+  interacting with a phone or tablet. These principles have been developed by the Android User
+  Experience Team to guide creation of the Android TV platform and the apps that run on it.</p>
+
+<h2>Casual Consumption</h2>
+
+<p>The TV is an entertainment interface, not a computer or mobile device. Optimize for
+  activities that put content at the center: from the casual posture of movie-watching, to
+  edge-of-seat, immersive gameplay, to hanging out with friends in a living room.</p>
+
+<p>Users expect immediate access to to content when they turn on a TV. Get users into the action
+  fast, be it the big game, their favorite show, or a game with friends. The next piece of content
+  to watch or play should only be a click or two away.</p>
+
+<p>
+  [add a visual]
+</p>
+
+
+<h2>Cinematic Experience</h2>
+
+<p>Create immersive experiences for the user. Design for as little user interface and as much
+  content as possible on each screen. Use visual imagery, movement and sound to inform and delight
+  users. Avoid using on-screen text to convey information and purpose. Tell your story with pictures
+  and sound.</p>
+
+<p>
+  [add a visual]
+</p>
+
+
+<h2>Simplicity</h2>
+
+<p>An Android TV should be simple and magical. It’s all about finding and enjoying content and
+  apps with the least amount of friction. Minimize the number of navigation steps required to
+  perform actions. Build apps with the fewest screens possible between app entry and content
+  immersion. Avoid making users enter text whenever possible, and use voice interfaces when you
+  require text input.</p>
+
+<p>
+  [add a visual]
+</p>
diff --git a/docs/html/design/tv/style.jd b/docs/html/design/tv/style.jd
new file mode 100644
index 0000000..479ed91
--- /dev/null
+++ b/docs/html/design/tv/style.jd
@@ -0,0 +1,108 @@
+page.title=Style for TV
+page.tags="design"
+@jd:body
+
+
+<p>Follow these style guidelines to create beautiful, functional apps for TV.</p>
+
+
+<h2>Layouts</h2>
+
+<p>The difference between a TV experience that feels right and one that does not greatly depends
+  on the number, spacing and size of on-screen elements. Although TV sizes and resolutions have
+  steadily increased over time, users expect TV experiences to be relatively simple and
+  uncluttered.</p>
+
+<p>The additional resolution and screen area afforded by modern displays is best used to display
+  things at better quality, rather than greater quantity. For example, use your layouts to show
+  large, beautiful pieces of content, or resize type for both easy reading and generous spacing.</p>
+
+<p>If you are creating an app for browsing and playing content, use the prebuilt fragments in the
+  Leanback support library. These layouts have been built specifically for use on TV devices with
+  the guidance of the Android User Experience team. For more information on using these classes,
+  see the <a href="{@docRoot}preview/tv/build-ui/index.html">User Interfaces</a> guide.
+</p>
+
+<p>Here are some additional recommendations for creating functional and attractive layout for TV
+  apps:</p>
+
+<ul>
+  <li><p>Build layouts designed for landscape orientation. TV screens always use in this
+      orientation.</p></li>
+  <li><p>Put on-screen navigational controls on the left or right side of the screen and
+      save the vertical space for content.</p></li>
+  <li><p>Create UIs that are divided into sections, by using Fragments and use view groups
+      like GridView instead of ListView to make better use of the horizontal screen space.</p></li>
+  <li><p>Add sufficient margins between layout controls to avoid a cluttered interface.</p></li>
+</ul>
+
+
+<h3>Screen Size</h3>
+
+<p>TV devices running Android are intended to operate at HD resolution (1920 x 1080 pixels) or
+  higher. Design your artwork assets for best viewing at this resolution.</p>
+
+
+<h3>Overscan</h3>
+
+<p>During the evolution of TV technology, overscan originally described an area of TV content
+  outside of a safe zone that most TVs could reliably display. Even on some of today’s HDTV flat
+  screens, areas outside that zone may not be visible.</p>
+
+<img src="{@docRoot}design/tv/images/overscan.png" alt="image alt text" />
+
+<p>Build a 10% margin into your TV screen designs to account for overscan area the TV may not
+  display correctly. On a 1920 x 1080 pixel screen, this margin should be a minimum of 27px from the
+  top and bottom edges and a minimum of 48px from the right and left edges of the picture.</p>
+
+
+<h2>Color</h2>
+
+<p>Color rendering on televisions can be imprecise compared to computer monitors or mobile
+  devices. LCD and Plasma TVs often apply smoothing and sharpening filters, and color rendering may
+  not match what you see on a computer screen.</p>
+
+<p>Subtle hue or brightness differences between elements may disappear or be over-emphasized on
+  TV screens. Some color gradient combinations will show bands. You should avoid pure whites and
+  highly saturated colors in large areas of the screen (especially reds, greens and blues). You
+  should also avoid using very dark or muddy colors, as TV settings may display these colors with
+  exaggerated contrast, causing them to be indistinguishable.</p>
+
+
+<h2>Typography</h2>
+
+<p>The text and controls in a TV application's UI should be easily visible and navigable from a
+  distance. The minimum recommended font size for TV is 12sp. The default text size setting should
+  be 18sp. We recommend the following guidelines for TV apps:</p>
+
+<ul>
+  <li>Browse Titles: Regular 44sp</li>
+  <li>Browse Menu Category Text: 20sp at 50% transparency</li>
+  <li>Browse Focused Menu Category Text: 24sp with no transparency</li>
+  <li>Row Category Titles focused: 20sp with no transparency</li>
+  <li>Row Category Titles focused: 20sp at 50% transparency</li>
+  <li>Details Content Titles: 34sp</li>
+  <li>Details Subtext: 14sp</li>
+</ul>
+
+<p>[visual showing text on a TV screen (sidebar position)]</p>
+
+<p>Some TVs have strong sharpness and contrast settings as their defaults. These picture
+  settings make thin and light typefaces look jagged and make the text difficult for people to read.
+  Therefore you should avoid thin or light typefaces on TV.</p>
+
+<h2>Text</h2>
+
+<p>Use text in TV apps sparingly. The position of users relative to a TV screen
+  (typically about 10 away) makes it harder for users to read text and the expectation of users in a
+  TV environment not conducive to reading. Follow these tips for the best handling of text in your
+  app:</p>
+
+<ul>
+  <li>Break text into small chunks that users can quickly scan.</li>
+  <li>Use light text on a dark background. This style is easier to read on a TV.</li>
+  <li>Avoid lightweight fonts or fonts that have both very narrow and very broad
+      strokes. Use simple sans-serif fonts and use anti-aliasing to increase readability.</li>
+  <li>Use layout-relative sizing rather than absolute sizing and density-independent
+      pixel units instead of absolute pixel units.</li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/design/tv/ui-overview.jd b/docs/html/design/tv/ui-overview.jd
new file mode 100644
index 0000000..c58c9cd
--- /dev/null
+++ b/docs/html/design/tv/ui-overview.jd
@@ -0,0 +1,63 @@
+page.title=UI Overview for TV
+page.tags="design"
+@jd:body
+
+<p>The Android TV system user interface provides the launch pad for your app's big screen
+  experience. It's important to understand how your app is presented in the main user interface and
+  how your app can help users get to the content they want quickly, including contributing content
+  suggestions to the recommendations row.</p>
+
+<p>This section provides quick overview of the Android TV user interface.</p>
+
+
+<h2>Home Screen</h2>
+
+<p>The Home Screen is the start of a TV user's experience, providing search, content
+  recommendations, access to apps and settings. The Home Screen provides a rich and cinematic
+  overview of apps and content.</p>
+
+<img src="{@docRoot}design/tv/images/atv-home.png" alt="TV Home screen" />
+
+
+<h2>Search</h2>
+
+<p>By bringing the power of Google search to the big screen, Android TV makes new, dynamic
+  connections between content - a favorite movie may connect to the discovery of a new music artist,
+  planning trip to Paris might surface new YouTube content and photos.</p>
+
+<img src="{@docRoot}design/tv/images/search.png" alt="Recommendations Row" />
+
+
+<h2>Recommendations</h2>
+
+<p>The recommendation row on Android TV is a central feature of the Home Screen that allows
+  users quick access to dynamic and relevant content for their media consumption activities. The
+  stream is optimized for quick browsing of personalized content and activity resumption (on the
+  device and across devices), while also providing a way for users to act on meaningful new content.</p>
+
+<img src="{@docRoot}design/tv/images/recommendations.png" alt="Recommendations Row" />
+
+<p>
+  The recommendations are based on the user’s recent and frequent usage behaviors, as well as
+  expressed content preferences. They are presented as cards that represent a system or app action,
+  notification, activity, or piece of actionable media. Your app can provide suggestions for the
+  recommendations row to help get your content noticed. To learn more, see
+  <a href="{@docRoot}preview/tv/build-ui/recommendations.html">Recommendations</a>.
+</p>
+
+
+<h2>Apps and Games</h2>
+
+<p>Apps and Games rows both have special areas on the Home Screen. Within these respective
+  areas, Apps and Games titles are reordered to reflect the user’s recent usage.</p>
+
+<img src="{@docRoot}design/tv/images/apps-games-rows.png" alt="Apps and Games Rows" />
+
+
+<h2>Settings</h2>
+
+<p>Access to Settings is found at the bottom of the Home Screen. From here, the user can access
+  Android and device-specific settings. Please see the "Settings" section for more detailed
+  information.</p>
+
+<img src="{@docRoot}design/tv/images/settings.png" alt="Settings Row" />
diff --git a/docs/html/distribute/engage/analytics.jd b/docs/html/distribute/engage/analytics.jd
new file mode 100644
index 0000000..5f7cade
--- /dev/null
+++ b/docs/html/distribute/engage/analytics.jd
@@ -0,0 +1,50 @@
+page.title=Understand User Behavior
+page.metaDescription=Use Google Analytics to learn what your users like and what keeps them coming back.
+page.tags="analytics, user behavior"
+page.image=/images/gp-analytics.jpg
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-analytics.jpg" style="width:320px">
+</div>
+
+
+<p>
+  Link your Google Play Developer Console with Google Analytics to learn much
+  more about how users interact with your app &mdash; before and after they
+  download it.
+</p>
+
+<p>
+  Start by discovering how many people visit your Google Play listing page,
+  where they come from, and how many go on to install your app. Once the app is
+  launched, use Google Analytics to see which of your features are most
+  popular, where power users spend their time, who tends to make in-app
+  purchases, and more.
+</p>
+
+<p>
+  Google Analytics delivers the numbers in real time, so you can act fast to
+  update your landing page and your app. <a href=
+  "http://www.google.com/analytics/mobile/">Learn more</a>.
+</p>
+
+<p>
+  If you have a Google Analytics account already, linking it to Google Play
+  takes just a few moments. You can also link your Google Analytics account to
+  Admob to start gaining more user insights to improve your in-app marketing.
+</p>
+
+  <div class="headerLine clearfloat">
+  <h2 id="related-resources">
+    Related Resources
+  </h2>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/engage/analytics"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
index 0417ba1..a25c3c6 100644
--- a/docs/html/distribute/engage/deep-linking.jd
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -1,13 +1,13 @@
 page.title=Deep Link to Bring Users Back
-page.metaDescription=Use deep links to bring your users into your apps from social posts or search.
+page.metaDescription=Use deep links to bring your users into your apps from social posts, search, or ads.
 page.tags="app indexing, google+ signin"
 page.image=/images/gp-listing-4.jpg
 
 @jd:body
 
 <p>
-  Use deep links to bring your users into your apps from social posts or
-  search.
+  Use deep links to bring your users into your apps from social posts,
+  search, or ads.
 </p>
 
 <div class="headerLine">
@@ -47,6 +47,11 @@
 <h2>Deep Linking from Google Search &mdash; App Indexing</h2>
 </div>
 
+
+<div style="float:right;">
+  <img src="/images/gp-listing-4.jpg" style="padding-top:1em;padding-left:2em;">
+</div>
+
 <p>
   Another way to bring users back to your apps is to apply for app indexing.
 </p>
@@ -60,11 +65,29 @@
   content</a>.
 </p>
 
-<div>
-  <img src="{@docRoot}images/gp-listing-4.jpg" style="padding-top:1em;">
+<div class="clearfloat" style="margin-top:2em;"></div>
+
+<div style="float:right;width:340px;padding-left:2em;">
+  <img src="/images/gp-ads-linking2.jpg" style="padding-top:1em;">
 </div>
 
-<div class="headerLine">
+<div class="headerLine ">
+<h2>Deep Linking from Google Ads</h2>
+</div>
+<p>
+  Ads can remind users about the apps they already have.
+</p>
+
+<p>
+  As with deep links from Google's organic search results, AdWords deep links
+  send users directly to the relevant pages in apps they already have on their
+  mobile device. A mobile search for "flights to London," for instance, could
+  take a user straight to the London page in a travel app. <a href=
+  "http://www.thinkwithgoogle.com/products/ads-apps.html"
+  class="external-link">Learn more</a>.
+</p>
+
+<div class="headerLine clearfloat">
   <h2 id="related-resources">
     Related Resources
   </h2>
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
index 0314f8c..596051a 100644
--- a/docs/html/distribute/engage/engage_toc.cs
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -37,6 +37,12 @@
   </li>
   <li class="nav-section">
     <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/analytics.html">
+        <span class="en">Understand User Behavior</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
         var:toroot?>distribute/engage/app-updates.html">
         <span class="en">Update Regularly</span></a>
     </div>
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
index f8cd1ee..2b103c3 100644
--- a/docs/html/distribute/engage/index.jd
+++ b/docs/html/distribute/engage/index.jd
@@ -15,8 +15,8 @@
 
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/engagelanding"
-    data-cardSizes="6x6"
-    data-maxResults="9">
+    data-cardSizes="9x6,9x6,6x6,6x6,6x6,9x6,9x6,6x6,6x6,6x6"
+    data-maxResults="10">
   </div>
 
   <h3>Related Resources</h3>
diff --git a/docs/html/distribute/engage/widgets.jd b/docs/html/distribute/engage/widgets.jd
index 286adea..6adb55c 100644
--- a/docs/html/distribute/engage/widgets.jd
+++ b/docs/html/distribute/engage/widgets.jd
@@ -1,5 +1,5 @@
 page.title=Build Useful Widgets
-page.metaDescription=Use widgets to remind users about important information in your apps and games, even when your apps are closed.
+page.metaDescription=Use home screen widgets to remind users about important information in your apps and games, even when your apps are closed.
 page.tags=""
 page.image=/images/gp-engage-0.jpg
 
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
index bcb1e52..9a847ff 100644
--- a/docs/html/distribute/monetize/ads.jd
+++ b/docs/html/distribute/monetize/ads.jd
@@ -10,17 +10,32 @@
 </div>
 
 <p>
-  In-app advertising offers a quick and easy way to incorporate a monetization
-  option into both your <a href=
+  Ads can be a quick and easy way to earn more from your <a href=
   "{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
   "{@docRoot}distribute/monetize/premium.html">premium</a>, and <a href=
-  "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps. </p>
+  "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps.
+  AdMob and the Google Mobile Ads SDK let you add advertising to your apps with
+  just a few lines of code.
+</p>
 
-<p>Using <a href=
+<p>
+  The question is: which model gets the best results for your app? Google's ad
+  tools are made to help you figure out what combination works best for both
+  your audience and your bottom line. </p>
+
+<p>Start by linking your AdMob and Google
+  Analytics accounts to get better insights and more earning power: for
+  instance, AdMob can promote in-app purchases to the people who buy them most
+  often, while showing income-generating ads to those less likely to buy right
+  now.
+</p>
+
+<p>
+  Using <a href=
   "http://www.google.com/ads/admob/monetize.html#subid=us-en-et-dac">AdMob</a>
-  and the <a href="{@docRoot}google/play-services/ads.html">Google
-  Mobile Ads SDK</a> included in Google Play Services, you’re able to add
-  advertising into your apps, with just a few lines of code.
+  and the <a href="{@docRoot}google/play-services/ads.html">Google Mobile Ads
+  SDK</a> included in Google Play Services, you’re able to add advertising into
+  your apps, with just a few lines of code.
 </p>
 
 <p>
@@ -30,36 +45,33 @@
 <ul>
   <li>
     <p>
-      <strong>Placement within your apps</strong> &mdash; Well placed ads will
-      optimize your revenue by making it more likely that users will ‘click
-      through’. Poorly placed ads can result in low click-through rates, and in
-      the worse cases poor rating and users rapidly abandoning your apps. You
-      can get advice on how to best place ads from the developer training on
-      <a href=
-      "{@docRoot}training/monetization/ads-and-ux.html">using
-      ads</a>.
+      <strong>Placement within your apps</strong> &mdash; Well-placed ads make
+      it more likely that users will click through and convert. Poorly-placed
+      ads lead to lower click-through rates, and even poor ratings and users
+      abandoning your apps. Our <a href=
+      "{@docRoot}training/monetization/ads-and-ux.html">developer training</a>
+      on using ads shows some of the best ways to place ads.
     </p>
   </li>
 
   <li>
     <p>
       <strong>Ad formats</strong> &mdash; Every app offers a different type of
-      experience for users, so it’s important to consider the format of ads
-      you’re using to ensure it’s compatible with the experience. While banner
-      ads may work well for a flashlight utility app, an immersive gaming app
-      may benefit more from a video interstitial. Mismatched ad formats may
-      negatively affect your users’ experience and ad revenue, so try to select
-      formats that fit well with the content and flow of your apps.
+      experience for users, so it’s important that your ad formats match that
+      experience. While banner ads may work well for a flashlight utility app,
+      an immersive gaming app may benefit more from a video interstitial.
+      Mismatched ad formats can make users unhappy and leave money on the
+      table.
     </p>
   </li>
 
   <li>
     <p>
-      <strong>Maximizing your performance</strong> &mdash; Ensure you’re optimizing
-      your advertising revenue by maximizing your CPMs <em>and</em> fill rate.
-      Often ad providers will cite very high CPMs but will have a low fill rate
-      that can severely decrease your effective CPM, so look at both of these
-      figures. Also consider using a <a href=
+      <strong>Maximizing your performance</strong> &mdash; Make sure you’re
+      optimizing your advertising revenue by maximizing your CPMs and fill
+      rate. Ad providers often cite their very high CPMs but don't mention low
+      fill rates that can severely decrease your effective CPM. Be sure to look
+      at both of these figures. Consider using a <a href=
       "https://support.google.com/admob/v2/answer/3063564?hl=en&amp;ref_topic=3063091#subid=us-en-et-dac">
       mediation</a> solution if you’d like to use multiple ad providers in your
       apps. Look for solutions that offer yield management or <a href=
@@ -71,30 +83,43 @@
 
   <li>
     <p>
-      <strong>Exercising control options</strong> &mdash; A variety of ads promoting a
-      broad selection of other services or apps may show up within you apps.
-      Depending on your goals and the type of experience you want to provide
-      your users, it may make sense to <a href=
+      <strong>Exercising control options</strong> &mdash; A variety of ads may
+      show up within your app. It may make sense to <a href=
       "https://support.google.com/admob/v2/answer/3150235?hl=enl#subid=us-en-et-dac">
-      block</a> certain advertisements from appearing. Some developers don’t
-      want apps in a similar category showing to their users, but some don’t
-      mind.
+      block</a> certain of those advertisements from appearing, depending on
+      your goals and the type of experience you want to provide. Some
+      developers, for instance, don’t want ads for apps in their same category
+      showing to their users, while others don’t mind at all.
     </p>
   </li>
 
   <li>
     <p>
-      <strong>Cross promoting your other apps</strong> &mdash; Ads can be used for
-      more than just earning revenue. Consider using <a href=
+      <strong>Cross promoting your other apps</strong> &mdash; Ads can do more
+      than earn revenue. Consider running <a href=
       "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
-      house ads</a> within your apps to create awareness and promote your
-      entire portfolio of apps. When launching new apps, an easy way to quickly
-      attract users is to promote directly to your existing customers.
+      house ads</a> within your apps to promote other apps in your portfolio.
+      When you launch a new app, this kind of promotion is a free and easy way
+      to attract new users quickly.
     </p>
   </li>
 </ul>
 
 <p>
+  Don't forget that paid channels like AdWords and YouTube can help you cast a
+  wider net by reaching targeted audiences outside the app ecosystem. They're a
+  great way to find new users at a price that you control. <a href=
+  "https://support.google.com/adwords/answer/2549053">Learn more</a>.
+</p>
+
+<p>
+  To start monetizing with ads, sign up for AdMob and integrate the Google
+  Mobile Ads SDK into your apps. If you also need to manage direct deals with
+  advertisers, consider using DoubleClick for Publishers Small Business.
+</p>
+
+
+<p>
   To start monetizing with ads sign up for <a href=
   "http://www.google.com/ads/admob/#subid=us-en-et-dac">AdMob</a> and integrate
   the <a href="https://developers.google.com/mobile-ads-sdk/download">Google
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
index 77ef609..a810f36 100644
--- a/docs/html/distribute/users/index.jd
+++ b/docs/html/distribute/users/index.jd
@@ -14,8 +14,8 @@
 
 <div class="resource-widget resource-flow-layout landing col-16"
   data-query="collection:distribute/users"
-  data-cardSizes="6x6, 6x6, 6x6, 9x6, 9x6, 6x6, 6x6, 6x6"
-  data-maxResults="8">
+  data-cardSizes="6x6"
+  data-maxResults="6">
 </div>
 
 <h3>Related resources</h3>
diff --git a/docs/html/distribute/users/promote-with-ads.jd b/docs/html/distribute/users/promote-with-ads.jd
new file mode 100644
index 0000000..1e28ae1
--- /dev/null
+++ b/docs/html/distribute/users/promote-with-ads.jd
@@ -0,0 +1,45 @@
+page.title=Promote Your App with Ads
+page.metaDescription=Promote your app through AdMob, AdWords, and YouTube to find new users at the right moment.
+page.image=/images/gp-ads-console.jpg
+page.tags="users, ads, analytics"
+
+@jd:body
+
+<p>
+  AdMob is Google's advertising platform for mobile apps. You can use it to
+  monetize your app and promote your apps, and you can link your Google
+  Analytics account to AdMob so you can analyze your apps &mdash; all in one
+  place.
+</p>
+
+<p>
+  <a href="http://www.google.com/ads/admob/">AdMob</a> is the largest mobile ad
+  app network. But you get more than just massive scale: AdMob will soon help
+  you find the right users in related apps. If your app is for bicycling, AdMob
+  can promote your app on other fitness and cycling-related apps worldwide.
+  <a href=
+  "https://apps.admob.com/admob/signup?subid=us-en-et-dac&_adc=ww-ww-et-admob2&hl=en">
+  Sign up for AdMob</a>.
+</p>
+
+<p>
+  AdMob also offers new solutions to help you achieve app-related goals such as
+  downloads, re-engagement and in-app purchases using Google search and the
+  Google Display Network. These solutions include streamlined campaign creation
+  flows and tools to track performance across the entire app lifecycle.
+  <a href="https://support.google.com/adwords/answer/2549053?hl=en">Learn
+  More</a>.
+</p>
+<div style="margin-top:2em;">
+  <img src="{@docRoot}images/gp-ads-console.jpg">
+</div>
+
+<div class="headerLine">
+<h2 id="related-resources">Related Resources</h2>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/promotewithads"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
index a2437a6..1f173cb 100644
--- a/docs/html/distribute/users/users_toc.cs
+++ b/docs/html/distribute/users/users_toc.cs
@@ -28,7 +28,12 @@
         </a>
     </div>
   </li>
-
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/promote-with-ads.html">
+          <span class="en">Promote with Ads</span>
+        </a>
+    </div>
+  </li>
 </ul>
 
 
diff --git a/docs/html/google/auth/api-client.jd b/docs/html/google/auth/api-client.jd
index 402a95f..5331d1e 100644
--- a/docs/html/google/auth/api-client.jd
+++ b/docs/html/google/auth/api-client.jd
@@ -1,4 +1,4 @@
-page.title=Accessing Google Play Services APIs
+page.title=Accessing Google APIs
 page.tags="oauth 2.0","GoogleAuthUtil"
 
 trainingnavtop=true
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 6ff00c0..b4028bd 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -3,11 +3,11 @@
      ########            ATTENTION             ###############
      ########                                  ###############
      #########################################################
-     
+
      IF YOU MAKE CHANGES TO THIS FILE, YOU MUST GENERATE THE
      GMS REFERENCE DOCS, BECAUSE THEY ARE NOT INCLUDED IN THE
      DOCS BUILD RULE.
-     
+
      #########################################################
      #########################################################
 ?>
@@ -73,11 +73,11 @@
     </div>
     <ul>
       <li><a href="<?cs var:toroot?>google/play-services/setup.html">
-          <span class="en">Setup</span></a>
+          <span class="en">Setting Up Google Play Services</span></a>
       </li>
       <li class="nav-section">
         <div class="nav-section-header"><a href="<?cs var:toroot?>google/auth/api-client.html">
-          <span class="en">Accessing Google Play Services APIs</span></a>
+          <span class="en">Accessing Google APIs</span></a>
         </div>
         <ul>
           <li>
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 744e191..4332953 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -1,4 +1,4 @@
-page.title=Set Up Google Play Services SDK
+page.title=Setting Up Google Play Services
 @jd:body
 
 
@@ -8,8 +8,7 @@
 
 <h2>In this document</h2>
 <ol>
-  <li><a href="#Install">Install the Google Play Services SDK</a></li>
-  <li><a href="#Setup">Set Up a Project that Uses Google Play Services</a></li>
+  <li><a href="#Setup">Add Google Play Services to Your Project</a></li>
   <li><a href="#Proguard">Create a Proguard Exception</a></li>
   <li><a href="#ensure">Ensure Devices Have the Google Play services APK</a></li>
 </ol>
@@ -18,12 +17,17 @@
 </div>
 </div>
 
+<script>
+$(document).ready(function() {
+  setupIdeDocToggle();
+});
+</script>
 
-    
+
 <p>To develop an app using the <a href="{@docRoot}reference/gms-packages.html">Google
-Play services APIs</a>, you must download the Google Play services SDK
-from the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.
-The download includes the client library and code samples.</p>
+Play services APIs</a>, you need to set up your project with the Google Play services SDK.
+<p>If you haven't installed the Google Play services SDK yet, go get it now by following the guide
+to <a href="{@docRoot}sdk/installing/adding-packages.html">Adding SDK Packages</a>.</p>
 
 <p>To test your app when using the Google Play services SDK, you must use either:</p>
 <ul>
@@ -33,68 +37,25 @@
   that runs the Google APIs platform based on Android 4.2.2 or higher.</li>
 </ul>
 
-<p>Ideally, you should develop and test your app on a variety of devices, including
-both phones and tablets.</p>
 
 
-<h2 id="Install">Install the Google Play Services SDK</h2>
+<h2 id="Setup">Add Google Play Services to Your Project</h2>
 
-<p>To install the Google Play services SDK for development:</p>
+<p>
+<select class="ide">
+  <option value="eclipse">Using Eclipse with ADT</option>
+  <option value="studio">Using Android Studio</option>
+  <option value="other">Using something else</option>
+</select>
+</p>
+
+
+<div class="select-ide studio">
 
 <ol>
-  <li>Launch the SDK Manager in one of the following ways:
-   <ul>
-    <li>In Android Studio, click <strong>SDK Manager</strong>
-<img src="{@docRoot}images/tools/sdk-manager-studio.png" style="vertical-align:bottom;margin:0;height:19px" />
-in the toolbar.</li>
-    <li>In Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
-    select <strong>Window</strong> &gt; <strong>Android SDK Manager</strong>.</li>
-    <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
-  SDK directory.</li>
-    <li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the
-  Android SDK, then execute <code>android sdk</code>.</li>
-    </ul>
-  </li>
-  <li>Install the Google Play services SDK.
-    <p>Scroll to the bottom of the package list, expand <b>Extras</b>, select
-    <b>Google Play services</b>, and install it. If you're using Android Studio, also install
-    <b>Google Repository</b> (it provides the Maven repository used for Gradle builds).</p>
-      <p>The Google Play services SDK is saved in your Android SDK environment at
-      <code>&lt;android-sdk&gt;/extras/google/google_play_services/</code>.</p>
-
-<p class="note"><strong>Note:</strong> Google Play services 4.0.30 (released
-November 2013) and newer versions require Android 2.3 or higher. If your app supports Android 2.2,
-you can continue development with the Google Play services SDK, but must instead install
-<b>Google Play services for Froyo</b> from the SDK Manager.</p>
-
-  </li>
-  <li>Install a compatible version of the Google APIs platform.
-    <p>If you want to test your app on the emulator, expand the directory for <b>Android 4.2.2
-    (API 17)</b> or a higher version, select <b>Google APIs</b>, and install it. Then create a
-    new <a href="{@docRoot}tools/devices/index.html">AVD</a> with Google APIs as
-    the platform target.</p>
-  </li>
-  <li>Make a copy of the Google Play services library project.
-    <p class="note"><strong>Note:</strong> If you are using Android Studio, skip this step.</p>
-    <p>Copy the library project at
-  <code>&lt;android-sdk&gt;/extras/google/google_play_services/libproject/google-play-services_lib/</code>        
-  to the location where you maintain your Android app projects.
-  <p>If you are using Eclipse, import the library project into your workspace.
-  Click <b>File > Import</b>, select <b>Android > Existing
-  Android Code into Workspace</b>, and browse to the copy of the library project to import it.</p>
-  </li>
-</ol>
-
-
-
-<h2 id="Setup">Set Up a Project that Uses Google Play Services</h2>
-
-<p><b>Using Android Studio:</b></p>
-
-<ol>
-  <li>Open the <code>build.gradle</code> file inside your application module directory. 
-      <p class="note"><strong>Note:</strong> Android Studio projects contain a top-level 
-      <code>build.gradle</code> file and a <code>build.gradle</code> file for each module. 
+  <li>Open the <code>build.gradle</code> file inside your application module directory.
+      <p class="note"><strong>Note:</strong> Android Studio projects contain a top-level
+      <code>build.gradle</code> file and a <code>build.gradle</code> file for each module.
       Be sure to edit the file for your application module. See
       <a href="{@docRoot}sdk/installing/studio-build.html">Building Your Project with
       Gradle</a> for more information about Gradle.</p></li>
@@ -128,8 +89,11 @@
 <p>You can now begin developing features with the
 <a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
 
+</div><!-- end studio -->
 
-<p><b>Using Eclipse or another IDE:</b></p>
+
+
+<div class="select-ide eclipse other">
 
 <p>To make the Google Play services APIs available to your app, you must reference the library
 project you created in step 4 of the <a href="#Install">installation instructions</a>.</p>
@@ -156,6 +120,9 @@
 you can begin developing features with the
 <a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
 
+</div><!-- end eclipse and other -->
+
+
 
 
 <h2 id="Proguard">Create a Proguard Exception</h2>
@@ -236,5 +203,6 @@
 that takes the user to Google Play Store to install the update.</p>
 
 
-<p>To then begin a connection to Google Play services, read <a
-href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>
+<p>To then begin a connection to Google Play services (required by most Google APIs such
+as Google Drive, Google+, and Games), read <a
+href="{@docRoot}google/auth/api-client.html">Accessing Google APIs</a>.</p>
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index b4617fb..5e6917b 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -4,12 +4,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>An activity provides a user interface for a single screen in your application</li>
-  <li>Activities can move into the background and then be resumed with their state restored</li>
-</ul>
-
 <h2>In this document</h2>
 <ol>
   <li><a href="#Creating">Creating an Activity</a>
diff --git a/docs/html/guide/components/bound-services.jd b/docs/html/guide/components/bound-services.jd
index 653c7a0..4215f0f2 100644
--- a/docs/html/guide/components/bound-services.jd
+++ b/docs/html/guide/components/bound-services.jd
@@ -6,12 +6,6 @@
 
 <div id="qv-wrapper">
 <ol id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>A bound service allows other components to bind to it, in order to interact with it and
-perform interprocess communication</li>
-  <li>A bound service is destroyed once all clients unbind, unless the service was also started</li>
-</ul>
 <h2>In this document</h2>
 <ol>
   <li><a href="#Basics">The Basics</a></li>
diff --git a/docs/html/guide/components/fragments.jd b/docs/html/guide/components/fragments.jd
index 32c9f99..0cc5f72 100644
--- a/docs/html/guide/components/fragments.jd
+++ b/docs/html/guide/components/fragments.jd
@@ -5,15 +5,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-
-  <h2>Quickview</h2>
-  <ul>
-    <li>Fragments decompose application functionality and UI into reusable modules</li>
-    <li>Add multiple fragments to a screen to avoid switching activities</li>
-    <li>Fragments have their own lifecycle, state, and back stack</li>
-    <li>Fragments require API Level 11 or greater</li>
-  </ul>
-
   <h2>In this document</h2>
   <ol>
     <li><a href="#Design">Design Philosophy</a></li>
diff --git a/docs/html/guide/components/processes-and-threads.jd b/docs/html/guide/components/processes-and-threads.jd
index c8c3764..e7ef7ba 100644
--- a/docs/html/guide/components/processes-and-threads.jd
+++ b/docs/html/guide/components/processes-and-threads.jd
@@ -5,13 +5,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>Every application runs in its own process and all components of the application run in that
-process, by default</li>
-  <li>Any slow, blocking operations in an activity should be done in a new thread, to avoid slowing
-down the user interface</li>
-</ul>
 
 <h2>In this document</h2>
 <ol>
diff --git a/docs/html/guide/components/services.jd b/docs/html/guide/components/services.jd
index da01d2c..6e22be8 100644
--- a/docs/html/guide/components/services.jd
+++ b/docs/html/guide/components/services.jd
@@ -3,14 +3,6 @@
 
 <div id="qv-wrapper">
 <ol id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>A service can run in the background to perform work even while the user is in a different
-application</li>
-  <li>A service can allow other components to bind to it, in order to interact with it and
-perform interprocess communication</li>
-  <li>A service runs in the main thread of the application that hosts it, by default</li>
-</ul>
 <h2>In this document</h2>
 <ol>
 <li><a href="#Basics">The Basics</a></li>
diff --git a/docs/html/guide/components/tasks-and-back-stack.jd b/docs/html/guide/components/tasks-and-back-stack.jd
index f818873..e054313 100644
--- a/docs/html/guide/components/tasks-and-back-stack.jd
+++ b/docs/html/guide/components/tasks-and-back-stack.jd
@@ -5,14 +5,6 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>All activities belong to a task</li>
-  <li>A task contains a collection of activities in the order in which the user interacts with
-them</li>
-  <li>Tasks can move to the background and retain the state of each activity in order for users
-to perform other tasks without losing their work</li>
-</ul>
 
 <h2>In this document</h2>
 <ol>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 0a234aa..ff08312 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -564,7 +564,11 @@
       <li><a href="<?cs var:toroot ?>guide/practices/tablets-and-handsets.html">
             <span class="en">Supporting Tablets and Handsets</span>
           </a></li>
-
+      <li>
+        <a href="<?cs var:toroot ?>guide/practices/verifying-apps-art.html">
+          <span class="en">Verifying App Behavior on ART</span>
+        </a>
+      </li>
     </ul>
   </li>
 
diff --git a/docs/html/guide/practices/verifying-apps-art.jd b/docs/html/guide/practices/verifying-apps-art.jd
new file mode 100644
index 0000000..0eedfaf
--- /dev/null
+++ b/docs/html/guide/practices/verifying-apps-art.jd
@@ -0,0 +1,296 @@
+page.title=Verifying App Behavior on the Android Runtime (ART)
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Quickview</h2>
+  <ul>
+    <li>The new Android runtime (ART) is available on some of the newest Android
+      devices, though all of them currently have Dalvik as the default
+      runtime.</li>
+    <li>App developers should make sure their apps are compatible with ART,
+      especially if you use JNI to run native code or if you use certain tools
+      that produce non-standard code (such as some obfuscators).</li>
+  </ul>
+
+  <h2 id="Contents">In this document</h2>
+ <ol>
+    <li><a href="#GC_Migration">Addressing Garbage Collection (GC) Issues</a></li>
+    <li><a href="#JNI_Issues">Preventing JNI Issues</a>
+      <ol>
+        <li><a href="#JNI_and_GC">Checking JNI code for garbage-collection
+          issues</a></li>
+        <li><a href="#Error_Handling">Error handling</a></li>
+        <li><a href="#Object_Model_Changes">Object model changes</a></li>
+      </ol>
+    </li>
+    <li><a href="#Stack_Size">Preventing Stack Size Issues</a></li>
+    <li><a href="#AOT_Fails">Fixing AOT Compilation Issues</a></li>
+    <li><a href="#Reporting_Problems">Reporting Problems</a></li>
+  </ol>
+  <h2>See also</h2>
+  <ol>
+    <li><a href="http://source.android.com/devices/tech/dalvik/art.html">Introducing ART</a></li>
+    <li><a
+href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
+Android JNI with CheckJNI</a></li>
+  </ol>
+</div>
+</div>
+
+<p>With Android 4.4, we are beginning to roll out a new Android runtime,
+<strong>ART</strong>. This runtime offers a number of new features that improve
+performance and smoothness of the Android platform and apps. (You can find more
+information about ART's new features in <a
+href="http://source.android.com/devices/tech/dalvik/art.html">Introducing
+ART</a>.)</p>
+
+<p>Currently, ART is available on a number of Android 4.4 devices, such as the
+Nexus 4, Nexus 5, Nexus 7, and Google Play edition devices.
+At this time, all devices still use Dalvik as the default runtime. We encourage
+you to test your apps for ART compatibility and to take advantage of ART's new
+features. However, for the time being, you should also take care to maintain
+compatibility with Dalvik.</p>
+
+<p>This document lets you know about things to watch for when migrating an
+existing app to be compatible with ART. Most apps should just work when
+running with ART. However, some techniques that work on Dalvik do not work on
+ART. This document discusses some of these issues.</p>
+
+<h2 id="GC_Migration">Addressing Garbage Collection (GC) Issues</h2>
+
+<p>Under Dalvik, apps frequently find it useful to explicitly call {@link
+java.lang.System#gc() System.gc()} to prompt garbage collection (GC). This should be
+far less necessary with ART, particularly if you're invoking garbage collection
+to prevent <a
+href="{@docRoot}/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a>-type
+occurrences or to reduce fragmentation. You can verify which runtime is in use
+by calling {@link java.lang.System#getProperty(java.lang.String)
+System.getProperty("dalvik.vm.version")}. If ART is in use, the property's value
+is <code>"2.0.0"</code> or higher.</p>
+
+<p>Furthermore, a compacting garbage collector is under development in the <a
+href="https://source.android.com">Android Open-Source Project (AOSP)</a> to
+improve memory management. Because of this, you should avoid using techniques
+that are incompatible with compacting GC (such as saving pointers to object
+instance data). This is particularly important for apps that make use of the
+Java Native Interface (JNI). For more information, see <a
+href="#JNI_Issues">Preventing JNI Issues</a>.</p>
+
+<h2 id="JNI_Issues">Preventing JNI Issues</h2>
+
+<p>ART's JNI is somewhat stricter than Dalvik's. It is an especially good idea
+to use CheckJNI mode to catch common problems. If your app makes use of C/C++
+code, you should review the following article:</p>
+
+<p><a
+href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
+Android JNI with CheckJNI</a></p>
+
+<h3 id="JNI_and_GC">Checking JNI code for garbage-collection issues</h3>
+
+<p>ART has a compacting garbage collector under development on the
+Android Open Source Project (AOSP). Once the compacting garbage collector is in
+use, objects may be moved in memory. If you use C/C++ code, do not
+perform operations that are incompatible with compacting GC. We have enhanced
+CheckJNI to identify some potential issues (as described in <a
+href="http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html">JNI
+Local Reference Changes in ICS</a>).</p>
+
+<p>One area to watch for in particular is the use of
+<code>Get...ArrayElements()</code> and <code>Release...ArrayElements()</code>
+functions. In runtimes with non-compacting GC, the
+<code>Get...ArrayElements()</code> functions typically return a reference to the
+actual memory backing the array object. If you make a change to one of the
+returned array elements, the array object is itself changed (and the arguments
+to <code>Release...ArrayElements()</code> are usually ignored). However, if
+compacting GC is in use, the <code>Get...ArrayElements()</code> functions may
+return a copy of the memory. If you misuse the reference when compacting GC is
+in use, this can lead to memory corruption or other problems. For example:</p>
+
+<ul>
+
+  <li>If you make any changes to the returned array elements, you must call the
+  appropriate <code>Release...ArrayElements()</code> function when you are done,
+  to make sure the changes you made are correctly copied back to the underlying
+  array object.</li>
+
+  <li>When you release the memory array elements, you must use the appropriate
+  mode, depending on what changes you made:
+
+    <ul>
+
+      <li>If you did not make any changes to the array elements, use
+      <code>JNI_ABORT</code> mode, which releases the memory without copying
+      changes back to the underlying array object.</li>
+
+      <li>If you made changes to the array, and do not need the reference any
+      more, use code <code>0</code> (which updates the array object and frees
+      the copy of the memory).</li>
+
+      <li>If you made changes to the array that you want to commit, and you want
+      to keep the copy of the array, use <code>JNI_COMMIT</code> (which updates
+      the underlying array object and retains the copy).</li>
+
+    </ul>
+
+  </li>
+
+  <li>When you call <code>Release...ArrayElements()</code>, return the same
+  pointer that was originally returned by <code>Get...ArrayElements()</code>. For
+  example, it's not safe to increment the original pointer (to scan through the
+  returned array elements) then pass the incremented pointer to
+  <code>Release...ArrayElements()</code>. Passing this modified pointer can cause
+  the wrong memory to be freed, resulting in memory corruption.</li>
+
+</ul>
+
+<h3 id="Error_Handling">Error handling</h3>
+
+<p>ART's JNI throws errors in a number of cases where Dalvik didn’t. (Once
+again, you can catch many such cases by testing with CheckJNI.)</p>
+
+<p>For example, if <code>RegisterNatives</code> is called with a method that
+does not exist (perhaps because the method was removed by a tool such as
+<strong>ProGuard</strong>), ART now properly throws {@link
+java.lang.NoSuchMethodError}:</p>
+
+<pre class="no-pretty-print">
+08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
+08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
+    no static or non-static method
+    "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+    at java.lang.Runtime.nativeLoad(Native Method)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+    at java.lang.Runtime.doLoad(Runtime.java:421)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+    at java.lang.Runtime.loadLibrary(Runtime.java:362)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+    at java.lang.System.loadLibrary(System.java:526)
+</pre>
+
+<p>ART also logs an error (visible in logcat) if <code>RegisterNatives</code> is
+called with no methods:</p>
+
+<pre class="no-pretty-print">
+W/art     ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
+methods for &lt;classname>
+</pre>
+
+<p>In addition, the JNI functions <code>GetFieldID()</code> and
+<code>GetStaticFieldID()</code> now properly throw {@link java.lang.NoSuchFieldError}
+instead of simply returning null. Similarly, <code>GetMethodID()</code> and
+<code>GetStaticMethodID()</code> now properly throw {@link java.lang.NoSuchMethodError}.
+This can lead to CheckJNI failures because of the unhandled exceptions or the
+exceptions being thrown to Java callers of native code. This makes it
+particularly important to test ART-compatible apps with CheckJNI mode.</p>
+
+<p>ART expects users of the JNI <code>CallNonvirtual...Method()</code> methods
+(such as <code>CallNonvirtualVoidMethod()</code>) to use the method's declaring
+class, not a subclass, as required by the JNI specification.</p>
+
+<h2 id="Stack_Size">Preventing Stack Size Issues</h2>
+
+<p>Dalvik had separate stacks for native and Java code, with a default Java
+stack size of 32KB and a default native stack size of 1MB. ART has a unified
+stack for better locality. Ordinarily, the ART {@link java.lang.Thread} stack
+size should be approximately the same as for Dalvik. However, if you explicitly
+set stack sizes, you may need to revisit those values for apps running in
+ART.</p>
+
+<ul>
+
+  <li>In Java, review calls to the {@link
+  java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
+  java.lang.String, long) Thread} constructor that specify an explicit stack
+  size. For example, you will need to increase the size if {@link
+  java.lang.StackOverflowError} occurs.</li>
+
+  <li>In C/C++, review use of <code>pthread_attr_setstack()</code> and
+  <code>pthread_attr_setstacksize()</code> for threads that also run Java code via
+  JNI. Here is an example of the error logged when an app attempts to call JNI
+  <code>AttachCurrentThread()</code> when the pthread size is too small:
+
+<pre class="no-pretty-print">F/art: art/runtime/thread.cc:435]
+    Attempt to attach a thread with a too-small stack (16384 bytes)</pre>
+  </li>
+
+</ul>
+
+<h2 id="Object_Model_Changes">Object model changes</h2>
+
+<p>Dalvik incorrectly allowed subclasses to override package-private methods.
+ART issues a warning in such cases:</p>
+
+<pre class="no-pretty-print">
+Before Android 4.1, method void com.foo.Bar.quux()
+would have incorrectly overridden the package-private method in
+com.quux.Quux
+</pre>
+
+<p>If you intend to override a class's method in a different package, declare the
+method as <code>public</code> or <code>protected</code>.</p>
+
+<p>{@link java.lang.Object} now has private fields. Apps that reflect on fields
+in their class hierarchies should be careful not to attempt to look at the
+fields of {@link java.lang.Object}. For example, if you are iterating up a class
+hierarchy as part of a serialization framework, stop when
+
+<pre>Class.getSuperclass() == java.lang.Object.class</pre>
+
+instead of continuing until the method returns <code>null</code>.</p>
+
+<p>Proxy {@link
+java.lang.reflect.InvocationHandler#invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[])
+InvocationHandler.invoke()} now receives <code>null</code> if there are no
+arguments instead of an empty array. This behavior was documented previously but
+not correctly handled in Dalvik. Previous versions of <a
+href="https://code.google.com/p/mockito/">Mockito</a> have difficulties with
+this, so use an updated Mockito version when testing with ART.</p>
+
+<h2 id="AOT_Fails">Fixing AOT Compilation Issues</h2>
+
+<p>ART's Ahead-Of-Time (AOT) Java compilation should work for all standard Java
+code. Compilation is performed by ART's
+<code>dex2oat</code> tool; if you encounter any issues related to
+<code>dex2oat</code> at install time, let us know (see <a
+href="#Reporting_Problems">Reporting Problems</a>) so we can fix them as quickly
+as possible. A couple of issues to note:</p>
+
+<ul>
+
+  <li>ART does tighter bytecode verification at install time than Dalvik does.
+  Code produced by the Android build tools should be fine. However, some
+  post-processing tools (especially tools that perform obfuscation) may produce
+  invalid files that are tolerated by Dalvik but rejected by ART. We have been
+  working with tool vendors to find and fix such issues. In many cases, getting
+  the latest versions of your tools and regenerating the DEX files can fix these
+  problems.</li>
+
+  <li>Some typical problems that are flagged by the ART verifier include:
+    <ul>
+      <li>invalid control flow</li>
+      <li>unbalanced <code>moniterenter</code>/<code>moniterexit</code></li>
+      <li>0-length parameter type list size</li>
+    </ul>
+  </li>
+
+  <li>Some apps have dependencies on the installed <code>.odex</code> file
+  format in <code>/system/framework</code>, <code>/data/dalvik-cache</code>, or
+  in {@link dalvik.system.DexClassLoader}’s optimized output directory. These
+  files are now ELF files and not an extended form of DEX files. While ART tries
+  to follow the same naming and locking rules as Dalvik, apps should not depend
+  on the file format; the format is subject to change without notice.</li>
+
+
+
+<h2 id="Reporting_Problems">Reporting Problems</h2>
+
+<p>If you run into any issues that aren’t due to app JNI issues, report
+them via the Android Open Source Project Issue Tracker at <a
+href="https://code.google.com/p/android/issues/list">https://code.google.com/p/android/issues/list</a>.
+Include an <code>"adb bugreport"</code> and a link to the app in the Google
+Play store if available. Otherwise, if possible, attach an APK that reproduces
+the issue. Note that issues (including attachments) are publicly
+visible.</p>
diff --git a/docs/html/images/gp-ads-console.jpg b/docs/html/images/gp-ads-console.jpg
new file mode 100644
index 0000000..158e31d
--- /dev/null
+++ b/docs/html/images/gp-ads-console.jpg
Binary files differ
diff --git a/docs/html/images/gp-ads-linking2.jpg b/docs/html/images/gp-ads-linking2.jpg
new file mode 100644
index 0000000..0c2f731
--- /dev/null
+++ b/docs/html/images/gp-ads-linking2.jpg
Binary files differ
diff --git a/docs/html/images/gp-analytics.jpg b/docs/html/images/gp-analytics.jpg
new file mode 100644
index 0000000..e1a92c7
--- /dev/null
+++ b/docs/html/images/gp-analytics.jpg
Binary files differ
diff --git a/docs/html/images/tools-home.png b/docs/html/images/tools-home.png
index 291a361..86a7414 100644
--- a/docs/html/images/tools-home.png
+++ b/docs/html/images/tools-home.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index a4b0683..de2980b 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,159 +1,95 @@
 fullpage=true
 page.viewport_width=970
-no_footer_links=true
-carousel=true
 excludeFromSuggestions=true
 page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
 page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
 
 @jd:body
 
+<!-- Top full-bleed carousel -->
+<div class="home-new-carousel-1">
+  <div class="fullscreen-carousel-content">
+    <div class="vcenter">
+      <div class="wrap clearfix">
+        <div class="resource-widget resource-flow-layout wrap col-16"
+          data-query="collection:index/primary"
+          data-resourceStyle="card"
+          data-sortOrder="-timestamp"
+          data-numStacks="3"
+          data-maxResults="4"
+          data-cardSizes="18x6,6x2,6x2,6x2">
+        </div> <!-- end .resource-widget -->
+      </div> <!-- end .wrap -->
+    </div> <!-- end .vcenter -->
+  </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
 
-<div class="wrap">
-    <!-- Slideshow -->
-    <div class="slideshow-container slideshow-home col-16">
-        <a href="" class="slideshow-prev">Prev</a>
-        <a href="" class="slideshow-next">Next</a>
-        <div class="frame">
-            <ul>
-                <!-- set explicit widths as needed to prevent overflow issues -->
+<div class="actions-bar">
+  <div class="wrap">
+    <div class="actions">
+      <div><a href="{@docRoot}sdk/index.html">Get the SDK</a></div>
+      <div><a href="{@docRoot}samples/index.html">Browse Samples</a></div>
+      <div><a href="//www.youtube.com/user/androiddevelopers">Watch Videos</a></div>
+      <div><a href="{@docRoot}distribute/googleplay/developer-console.html">Manage Your Apps</a></div>
+    </div><!-- end .actions -->
+  </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
 
 
-                <li class="item carousel-home">
-                  <div class="content-left col-10" style="width:580px;">
-                    <a href="{@docRoot}wear/index.html">
-                      <img src="{@docRoot}images/home/aw_dac.png" style="margin-top:50px" >
-                    </a>
-                  </div>
-                  <div class="content-right col-5" style="width:280px;">
-                    <h1>Introducing Android Wear</h1>
-                    <p>We’re extending the Android platform to wearables. You can start building richer wearable experiences for your apps today using the enhanced Notification APIs in this Developer Preview.</p>
-                    <p>We can’t wait to see what you will create.</p>
-                    <p><a href="{@docRoot}wear/index.html" class="button">Learn more</a></p>
-                  </div>
-                </li>
 
-
-                <li class="item carousel-home">
-                    <div class="content-left col-11" style="padding-top:65px;">
-                      <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
-                      <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
-                        <div id="ytapiplayer">
-                          <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
-                        </div>
-                        <script type="text/javascript">
-                            var params = { allowScriptAccess: "always" };
-                            var atts = { id: "ytapiplayer" };
-                            swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
-                              "ytapiplayer", "600", "336", "8", null, null, params, atts);
-
-                            // Callback used to pause/resume carousel based on video state
-                            function onytplayerStateChange(newState) {
-                               var isPaused = $("#pauseButton").hasClass("paused");
-                               if ((newState == 1) || (newState == 3)) {
-                               // if playing or buffering, pause the carousel
-                                 if (!isPaused) {
-                                    $("#pauseButton").click();
-                                 }
-                               } else {
-                               // otherwise, make sure carousel is running
-                                 if (isPaused) {
-                                    $("#pauseButton").click();
-                                 }
-                               }
-                            }
-
-                            // Callback received when YouTube player loads to setup callback (above)
-                            function onYouTubePlayerReady(playerId) {
-                              var ytplayer = document.getElementById("ytapiplayer");
-                              ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
-                            }
-
-                        </script>
-                      </div>
-                    </div>
-                    <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
-                    <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
-                      has helped them double revenue every six months.</p>
-                      <p><a href="{@docRoot}distribute/stories/index.html" class="button">Watch more videos </a></p>
-                    </div>
-                </li>
-
-                <li class="item carousel-home">
-                  <div class="content-left col-7" style="width:400px;">
-                    <a href="{@docRoot}about/versions/kitkat.html">
-                      <img src="{@docRoot}images/home/kk-hero.jpg" width="242" style="padding-top:72px;">
-                    </a>
-                  </div>
-                  <div class="content-right col-4" style="width:340px;">
-                    <h1>Android 4.4 KitKat!</h1>
-                    <p>A new version of Android is here, with great new features, APIs, and tools for developers.</p>
-                    <p>Android 4.4 is built to run on more devices than ever before, and gives you more ways to showcase your content and create beautiful, useful, and innovative apps.</p>
-                    <p>Learn about what's new in the Platform Highlights and see the API Overview for details.</p>
-                    <p><a href="{@docRoot}about/versions/kitkat.html" class="button">Check out the highlights</a></p>
-                  </div>
-                </li>
-
-                <li class="item carousel-home">
-                  <div class="content-left col-11" style="padding-top:65px;">
-                    <a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1">
-                      <img src="{@docRoot}images/title-devbytes-kk.jpg" style="margin-top:0px;width:600px;">
-                    </a>
-                  </div>
-                  <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">DevBytes: <br />Android 4.4</h1>
-                    <p>Join the DevBytes team for a look at what's new in Android 4.4 KitKat&nbsp;&mdash; new ways to make your apps beautiful, printing, storage access framework, and more.</p>
-                    <p><a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1" class="button">Watch the video </a></p>
-                  </div>
-                </li>
-
-                <li class="item carousel-home">
-                  <div class="content-left col-19" style="width:580px;">
-                    <a href="{@docRoot}design/patterns/new.html">
-                      <img src="{@docRoot}design/media/design_elements_landing.png" style="margin-top:30px">
-                    </a>
-                  </div>
-                  <div class="content-right col-4" style="width:280px;">
-                    <h1>Design for Android KitKat</h1>
-                    <p>Android KitKat brings a refreshed UI with updated styles, patterns, and gestures to use in your apps. </p>
-                    <p>We've updated the Android Design guidelines and added new pages on branding, fullscreen, and more. </p>
-                    <p><a href="{@docRoot}design/patterns/new.html" class="button">See what's new</a></p>
-                  </div>
-                </li>
-
-                <li class="item carousel-home">
-                  <div class="content-left col-11" style="padding-top:65px;">
-                    <a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1">
-                      <img src="{@docRoot}images/title-adia-kk.png" style="margin-top:0px;width:600px;">
-                    </a>
-                  </div>
-                  <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">ADIA: <br />Android 4.4</h1>
-                    </p>Join the Android Design in Action team for a walkthrough of new developer features, UX changes, and updates to design guidelines in Android 4.4.</p>
-                    <p><a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1" class="button">Watch the video </a></p>
-                  </div>
-                </li>
-           </ul>
+<div class="landing-rest-of-page">
+  <div class="landing-section" style="background-color:#f5f5f5">
+    <div class="wrap">
+      <div class="landing-section-header">
+        <div class="landing-h1">Android, Everywhere You Need It</div>
+        <div class="landing-subhead">
+          Android runs on hundreds of millions of handheld devices around the world, <br /> and it now supports these exciting, new form-factors.
         </div>
-    </div>
+      </div>
+      <div class="landing-body">
+        <div class="landing-breakout cols">
 
-<!-- /End slideshow -->
+         <!-- <div class="resource-widget resource-flow-layout col-16" data-query="collection:index/devices"
+          data-sortorder="" data-cardsizes="6x6, 6x6, 6x6" data-maxresults="3"></div>-->
 
-    <a href="" id="pauseButton" style="display:none">pause</a>
+          <div class="col-3-wide">
+            <img src="" alt="">
 
+            <p>Wear</p>
+            <p class="landing-small">
+              Provide information on-the-go for your users, whenever they need it.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}wear">Learn about Android Wear</a>
+            </p>
+          </div>
 
-</div>
-<div class="wrap" style="padding-bottom:20px">
-    <!-- Section links -->
-    <div class="home-sections">
-        <ul>
-            <li><a href="{@docRoot}about/index.html">About Android</a></li>
-            <li><a href="{@docRoot}sdk/index.html">Get the SDK</a></li>
-            <li><a href="http://source.android.com">Open Source</a></li>
-            <li><a href="{@docRoot}support.html">Support</a></li>
-            <li class="last"><a href="{@docRoot}legal.html">Legal</a></li>
-        </ul>
-    </div>
-    <!-- /Section links -->
-</div>
+          <div class="col-3-wide">
+            <img src="" alt="">
+
+            <p>TV</p>
+            <p class="landing-small">
+              Build your apps for the big screen and bring your content to life.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}tv">Learn about Android TV</a>
+            </p>
+          </div>
+
+          <div class="col-3-wide">
+            <img src="" alt="">
+
+            <p>Auto</p>
+            <p class="landing-small">
+              Extend your music apps to automobile
+              entertainment systems.
+            </p>
+            <p class="landing-small">
+              <a href="{@docRoot}auto">Learn about Android Auto</a>
+            </p>
+          </div>
+
+        </div>
+      </div>
+    </div>  <!-- end .wrap -->
+  </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 8a4ac47..ca19c02 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1,4 +1,21 @@
 var RESOURCE_COLLECTIONS = {
+  "index/primary": {
+    "title": "",
+    "resources": [
+      "preview/index.html",
+      "preview/material/index.html",
+      "preview/material/index.html",
+      "preview/material/index.html" 
+    ]
+  },
+  "index/devices": {
+    "title": "",
+    "resources": [
+      "wear/index.html",
+      "tv/index.html",
+      "auto/index.html"
+    ]
+  },
   "launch/static": {
     "title": "",
     "resources": [
@@ -49,7 +66,8 @@
       "distribute/users/your-listing.html",
       "distribute/users/build-buzz.html",
       "distribute/users/build-community.html",
-      "distribute/users/expand-to-new-markets.html"
+      "distribute/users/expand-to-new-markets.html",
+      "distribute/users/promote-with-ads.html"
     ]
   },
   "distribute/engagelanding": {
@@ -60,6 +78,7 @@
       "distribute/engage/easy-signin.html",
       "distribute/engage/deep-linking.html",
       "distribute/engage/game-services.html",
+      "distribute/engage/analytics.html",
       "distribute/engage/app-updates.html",
       "distribute/engage/community.html",
       "distribute/engage/video.html"
@@ -214,6 +233,13 @@
       "distribute/stories/localization.html"
     ]
   },
+  "distribute/users/promotewithads": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+      "distribute/essentials/optimizing-your-app.html"
+    ]
+  },
   "distribute/users/buildbuzz": {
     "title": "",
     "resources": [
@@ -394,6 +420,14 @@
       "http://play.google.com/about/developer-content-policy.html"
     ]
   },
+  "distribute/engage/analytics": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/analytics/mobile/",
+      "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
+      "https://developers.google.com/analytics/devguides/collection/android/"
+    ]
+  },
   "distribute/engage/widgets": {
     "title": "",
     "resources": [
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index f26b747b..d8db5bf 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -726,6 +726,21 @@
     "tags": [
       "#engagement",
     ],
+    "url": "http://www.google.com/analytics/mobile/",
+    "timestamp": 1383243492000,
+    "image": "http://www.google.com//analytics/images/heros/mobile-index.jpg",
+    "title": "Google Mobile App Analytics",
+    "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
+    "keywords": ["analytics,user behavior"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#engagement",
+    ],
     "url": "https://developers.google.com/app-indexing/",
     "timestamp": 1383243492000,
     "image": "https://developers.google.com/app-indexing/images/allthecooks_srp.png",
@@ -1101,4 +1116,17 @@
     "type": "Google+",
     "titleFriendly": ""
   },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["analytics"],
+    "url": "https://developers.google.com/analytics/devguides/collection/android/",
+    "timestamp": null,
+    "image": "https://developers.google.com/analytics/images/home/gear-logo.png",
+    "title": "Google Mobile App Analytics SDK",
+    "summary": "The Google Analytics for Mobile Apps SDKs make it easy for you to implement Google Analytics in your mobile application.",
+    "keywords": ["analytics, user behavior"],
+    "type": "sdk",
+    "titleFriendly": ""
+  }
 ]); 
\ No newline at end of file
diff --git a/docs/html/jd_tag_helpers.js b/docs/html/jd_tag_helpers.js
index ca01386..b0fe67a 100644
--- a/docs/html/jd_tag_helpers.js
+++ b/docs/html/jd_tag_helpers.js
@@ -7,6 +7,7 @@
 }
 
 var ALL_RESOURCES = mergeArrays(
+  ABOUT_RESOURCES,
   DESIGN_RESOURCES,
   DISTRIBUTE_RESOURCES,
   GOOGLE_RESOURCES,
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
new file mode 100644
index 0000000..40618a3
--- /dev/null
+++ b/docs/html/preview/api-overview.jd
@@ -0,0 +1,698 @@
+page.title=L Developer Preview APIs
+excludeFromSuggestions=true
+sdk.platform.apiLevel=20
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document
+    <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle">
+        <span class="more">show more</span>
+        <span class="less" style="display:none">show less</span></a></h2>
+
+<ol id="toc44" class="hide-nested">
+  <li><a href="#Behaviors">Important Behavior Changes</a>
+    <ol>
+      <li><a href="#BehaviorNotifications">If your app implements notifications...</a></li>
+      <li><a href="#BehaviorFullscreen">If your app uses fullScreenIntent...</a></li>
+      <li><a href="#BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</a></li>
+    </ol>
+  </li>
+  <li><a href="#UI">User Interface</a>
+    <ol>
+      <li><a href="#MaterialDesign">Material design support</a></li>
+      <li><a href="#LockscreenNotifications">Lockscreen notifications</a></li>
+      <li><a href="#NotificationsMetadata">Notifications metadata</a></li>
+      <li><a href="#Recents">Concurrent documents and activities in Recents screen</a></li>
+      <li><a href="#WebView">WebView updates</a></li>
+    </ol>
+  </li>
+  <li><a href="#UserInput">User Input</a>
+    <ol>
+      <li><a href="#IME">IME bug fixes and improvements</a></li>
+    </ol>
+  </li>
+  <li><a href="#Animations">Animation &amp; Graphics</a>
+    <ol>
+      <li><a href="#OpenGLES-3-1">Support for OpenGL ES 3.1</a></li>
+    </ol>
+  </li>
+  <li><a href="#Multimedia">Multimedia</a>
+    <ol>
+      <li><a href="#Camera-v2">Camera V2</a></li>
+      <li><a href="#AudioPlayback">Audio playback</a></li>
+      <li><a href="#MediaPlaybackControl">Media playback control</a></li>
+    </ol>
+  </li>
+  <li><a href="#Storage">Storage</a>
+    <ol>
+      <li><a href="#DirectorySelection">Directory selection</a></li>
+    </ol>
+  </li>
+  <li><a href="#Wireless">Wireless and Connectivity</a>
+    <ol>
+      <li><a href="#Multinetwork">Dynamic network selection and seamless handoff</a></li>
+      <li><a href="#BluetoothBroadcasting">Bluetooth broadcasting</a></li>
+      <li><a href="#NFCEnhancements">NFC enhancements for payments</a></li>
+    </ol>
+  </li>
+  <li><a href="#Power">Power Efficiency</a>
+    <ol>
+      <li><a href="#JobScheduler">Scheduling Jobs</a></li>
+      <li><a href="#PowerMeasurementTools">Developer tools and APIs for power measurement</a>
+    </ol>
+  </li>
+  <li><a href="#Enterprise">Enterprise</a>
+    <ol>
+      <li><a href="#ManagedProvisioning">Managed provisioning</a></li>
+    </ol>
+  </li>
+  <li><a href="#Printing">Printing Framework</a>
+    <ol>
+      <li><a href="#PDFRender">PDF rendering</a></li>
+    </ol>
+  </li>
+  <li><a href="#TestingA11y">Testing &amp; Accessibility</a>
+    <ol>
+      <li><a href="#TestingA11yImprovements">Testing and accessibility improvements</a></li>
+    </ol>
+  </li>
+  <li><a href="#Manifest">Manifest Declarations</a>
+    <ol>
+      <li><a href="#ManifestFeatures">Declarable required features</a></li>
+      <li><a href="#ManifestPermissions">User permissions</a></li>
+    </ol>
+  </li>
+</ol>
+
+<h2>See also</h2>
+<ol>
+<li><a href="{@docRoot}sdk/api_diff/20/changes.html">API
+Differences Report &raquo;</a> </li>
+</ol>
+
+</div>
+</div>
+
+<p>L is an upcoming release for the Android platform
+that offers new features for users and app developers. This document provides
+an introduction to the most notable new APIs.</p>
+
+<p>L is currently available as a <strong>developer preview</strong> intended
+for early adopters and testers. If you are interested in influencing the
+direction of the Android framework,
+<a href="{@docRoot}preview/setup-sdk.html">give the L Developer Preview a
+try</a> and send us your feedback!</p>
+
+<p class="caution"><strong>Caution:</strong>You should not publish apps
+using L Developer Preview to the Google Play store.</p>
+
+<h2 id="Behaviors">Important Behavior Changes</h2>
+
+<p>If you have previously published an app for Android, be aware that your app
+  might be affected by changes in L.</p>
+
+<h3 id="BehaviorNotifications">If your app implements notifications...</h3>
+
+<p>Notifications will be drawn with dark text atop white (or very light)
+backgrounds to match the new material design widgets. Make sure that all your
+notifications look right with the new color scheme. You should remove or update
+assets and text styles that involve color. The system will automatically invert
+action icons in notifications. Use
+{@code android.app.Notification.Builder.setColor()} to set an accent color
+in a circle behind your {@code Notification.icon} image.</p>
+
+<p>The system will ignore all non-alpha channels in action icons and the main
+notification icon, so you should assume that these icons will be alpha-only.
+</p>
+
+<p>If you are currently adding sounds and vibrations to your notifications by
+using the {@link android.media.Ringtone}, {@link android.media.MediaPlayer},
+or {@link android.os.Vibrator} classes, make sure to remove this code so that
+the system can present notifications correctly in Do not disturb mode. You
+should use the {@link android.app.Notification.Builder} methods instead to add
+sounds and vibration.
+</p>
+
+<h3 id="BehaviorMediaControl">If your app uses RemoteControlClient...</h3>
+
+<p>Lockscreens in L will not show transport controls for your
+{@link android.media.RemoteControlClient}. Instead, your app can provide
+media playback control from the lockscreen through a media notification. This
+gives your app more control over the presentation of media buttons, while
+providing a consistent experience for users across the lockscreen and
+unlocked device.</p>
+
+<p>You must call {@code Notification.Builder.setVisibility(Notification.VISIBILITY_PUBLIC)} to mark your media notification as safe to reveal, even when the lockscreen is secured
+with a PIN, pattern, or password.</p>
+
+<h3 id="BehaviorFullscreen">If your app uses fullScreenIntent...</h3>
+
+<p>Notifications now appear in a small floating window if all these conditions
+are met: the user’s activity is in fullscreen mode, the screen is on, and the
+device is unlocked. If your app implements fullscreen activities, make sure that
+these heads-up notifications are presented correctly.</p>
+
+<h3 id="BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</h3>
+
+<p>With the introduction of the new document tasks feature in L (see below),
+the {@code android.app.ActivityManager.getRecentTasks()} method is now
+deprecated to improve user privacy. For backwards
+compatibility, it will still return a small subset of its data including the
+calling application’s own tasks and possibly some other non-sensitive tasks
+such as home. If your app is using this method to retrieve its own tasks,
+use {@code android.app.ActivityManager.getAppTasks()} instead to retrieve that
+information.</p>
+
+<h2 id="UI">User Interface</h2>
+
+<h3 id="MaterialDesign">Material design support</h3>
+
+<p>The L Developer Preview adds support for the material design style. You can create
+material design apps that are visually dynamic and have UI element transitions
+which feel natural and delightful to users. This support includes:</p>
+<ul>
+  <li>The Material theme</li>
+  <li>View shadows</li>
+  <li>The {@code RecyclerView} widget</li>
+  <li>Drawable animation and styling effects</li>
+  <li>Material design animation and activity transition effects</li>
+  <li>Animators for view properties based on the state of a view</li>
+  <li>Customizable UI widgets and app bars with color palettes that you control</li>
+</ul>
+<p>To learn more about adding material design functionality to your app, see
+<a href="{@docRoot}preview/material/index.html">Material design on Android</a>.</p>
+
+<h3 id="LockscreenNotifications">Lockscreen notifications</h3>
+<p>Lockscreens in the L Developer Preview have the ability to present notifications.
+Users can choose via <em>Settings</em> whether to allow sensitive notification
+content to be shown over a secure lockscreen.</p>
+
+<p>Your app can control the level of detail visible when its notifications are
+displayed over the secure lockscreen. To control the visibility level, call
+{@code android.app.Notification.Builder.setVisibility()} and specify one of these
+values:</p>
+<ul>
+<li>{@code VISIBILITY_PRIVATE}. Shows basic information, such as the
+notification’s icon, but hides the notification’s full content. If you want to
+provide a redacted public version of your notification for the system to display
+on a secure lockscreen, set the public notification object in the <code>publicVersion</code>
+field.</li>
+<li>{@code VISIBILITY_PUBLIC}. Shows the notification’s full content. This is
+  the system default if visibility is left unspecified.</li>
+<li>{@code VISIBILITY_SECRET}. Shows only the most minimal information,
+excluding even the notification’s icon.</li>
+</ul>
+
+<h3 id="NotificationsMetadata">Notifications metadata</h3>
+<p>The L Developer Preview uses metadata associated with your app notifications
+to more intelligently sort your notifications. The metadata you set also
+controls how the system presents your app notifications when the user is in <em>Do
+not disturb</em> mode. When constructing your notification, you can call the
+following methods in {@code android.app.Notification.Builder}:</p>
+
+<ul>
+<li>{@code setCategory()}. Allows the system to handle your app notifications
+in <em>Do not disturb mode</em> (for example, if your notification represents an
+incoming call, instant message, or alarm).</li>
+<li>{@code setPriority()}. Notifications with the priority field set to
+{@code PRIORITY_MAX} or {@code PRIORITY_HIGH} will appear in a small floating
+window if the notification also has sound or vibration.</li>
+<li>{@code addPerson()}. Allows you to add a list of people to a notification.
+Your app can use this to signal to the system that it should group together
+notifications from the specified people, or rank notifications from these
+people as being more important.</li>
+</ul>
+
+<h3 id="Recents">Concurrent documents and activities in the Recents screen</h3>
+
+<p>In previous releases, the
+<a href="{@docRoot}design/get-started/ui-overview.html">Recents screen</a>
+could only display a single task for each app that the user interacted with
+most recently. The L Developer Preview allows your app to open additional tasks
+for concurrent activities or documents. This feature facilitates multitasking
+by letting users quickly switch between individual activities and documents
+from the Recents screen. Examples of such concurrent tasks might include web
+pages in a browser app, documents in a productivity app, concurrent matches in
+a game, or chats in a messaging app. Your app can manage its tasks
+through the {@code android.app.ActivityManager.AppTask} class.</p>
+
+<p>To insert a logical break so that the system treats your activity as a new
+document, use {@code android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT} when
+launching the activity with {@link android.app.Activity#startActivity(android.content.Intent) startActivity()}. You can also get this behavior by declaring the
+<a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
+attribute {@code documentLaunchMode="intoExisting"} or {@code ="always"} in your
+manifest.</p>
+
+<p>You can also mark that a task should be removed from the Recents screen
+when all its activities are closed by using {@code android.content.Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} when starting the root activity for
+the task. You can also set this behavior for an activity by declaring the
+<a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
+attribute {@code autoRemoveFromRecents=“true”} in your manifest.</p>
+
+<p>To avoid cluttering the Recents screen, you can set the maximum number of
+tasks from your app that can appear in the Recents screen through the
+<a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a> attribute {@code android:maxRecent}. The current maximum that can be specified
+is 100 tasks per user.</a></p>
+
+<h3 id="WebView">WebView updates</h3>
+<p>The L Developer Preview updates the {@link android.webkit.WebView}
+implementation to Chromium M36, bringing security and stability enhancements,
+as well as bug fixes. The default user-agent string for a
+{@link android.webkit.WebView}  running on the L Developer Preview has
+been updated to incorporate 36.0.0.0 as the version number.</p>
+
+<p>Additionally, this release brings support for the
+<a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">WebAudio</a>, <a href="https://www.khronos.org/webgl/">WebGL</a>, and
+<a href="http://www.webrtc.org/">WebRTC</a> open standards. To learn more about
+the new features included in this release, see <a href="https://developer.chrome.com/multidevice/webview/overview">WebView for Android</a>.</p>
+
+<h2 id="UserInput">User Input</h2>
+
+<h3 id="IME">IME bug fixes and improvements</h3>
+
+<p>Beginning in the L Developer Preview, users can more easily switch between
+all input method editors (IME) <a href="{@docRoot}guide/topics/text/creating-input-method.html">supported by the platform</a>. Performing the designated
+switching action (usually touching a Globe icon on the soft keyboard) will cycle
+among all such IMEs. This change takes place in
+{@code android.view.inputmethod.InputMethodManager.shouldOfferSwitchingToNextInputMethod()}.</p>
+
+<p>In addition, the framework will now check whether the next IME includes a
+switching mechanism at all, thus supporting switching to the IME after it. An
+IME with a switching mechanism will not cycle to an IME without one. This
+change takes place in
+{@code android.view.inputmethod.InputMethodManager.switchToNextInputMethod()}.
+
+<p>To see an example of how to use the updated IME-switching APIs, refer to the
+updated soft-keyboard implementation sample in this release.</p>
+
+<h2 id="Animations">Animation &amp; Graphics</h2>
+
+<h3 id="OpenGLES-3-1">Support for OpenGL ES 3.1</h3>
+<p>The L Developer Preview adds Java interfaces and native support for OpenGL
+ES 3.1. Key new functionality provided in OpenGL ES 3.1 includes:</p>
+
+<ul>
+<li>Compute shaders
+<li>Separate shader objects
+<li>Indirect draw commands
+<li>Enhanced texturing functionality
+<li>Shading language improvements
+<li>Optional extensions for per-sample shading, advanced blending modes, and more
+<li>Backward compatibility with OpenGL ES 2.0 and 3.0
+</ul>
+
+<p>The Java interface for OpenGL ES 3.1 on Android is provided with GLES31. When using OpenGL ES 3.1, be sure that you declare it in your manifest file with the
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a> tag and the {@code android:glEsVversion} attribute. For example:</p>
+
+<pre>
+&lt;manifest&gt;
+    &lt;uses-feature android:glEsVersion="0x00030001" /&gt;
+    ...
+&lt;/manifest&gt;
+</pre>
+
+<p>For more information about using OpenGL ES, including how to check the device’s supported OpenGL ES version at runtime, see the <a href="{@docRoot}/guide/topics/graphics/opengl.html">OpenGL ES API guide</a>.</p>
+
+<h2 id="Multimedia">Multimedia</h2>
+
+<h3 id="Camera=v2">Camera v2 API</h3>
+
+<p>The L Developer Preview introduces the new {@code android.hardware.camera2}
+API to facilitate fine grain photo capture and image processing. You can now programmatically access the camera devices available to the system with {@code CameraManager.getCameraIdList()} and connect to a specific device with {@code CameraManager.openCamera()}. To start capturing images, you
+need to create a {@code CameraCaptureSession} and specify the
+{@link android.view.Surface} objects to send the captured images. The {@code CameraCaptureSession} can be configured to take single shots or multiple images
+in a burst.</p>
+
+<p>To be notified when new images are captured, implement the
+{@code CameraCaptureSession.CaptureListener()} interface and set it in your
+capture request. Now when the system completes the image capture request, your
+{@code CameraCaptureSession.CaptureListener()} receives a call to
+{@code onCaptureCompleted()}, providing you with the image capture metadata in a
+{@code CaptureResult}.</p>
+
+<h3 id="AudioPlayback">Audio playback</h3>
+<p>This release includes the following changes for
+  {@code android.media.AudioTrack}:</p>
+<ul>
+  <li>Your app can now supply audio data in floating-point format
+({@code android.media.AudioFormat.ENCODING_PCM_FLOAT}). This permits greater
+dynamic range, more consistent precision, and greater headroom. Floating-point arithmetic is especially useful during intermediate calculations. Playback
+end-points use integer format for audio data, and with lower bit-depth. In L
+Developer Preview, portions of the internal pipeline are not yet floating-point.
+  <li>Your app can now supply audio data as a {@code ByteBuffer}, in the same
+format as provided by {@code MediaCodec}.
+  <li>The {@code WRITE_NON_BLOCKING} option can simplify buffering and
+    multithreading for some apps.
+</ul>
+
+<h3 id="MediaPlaybackControl">Media playback control</h3>
+<p>You can now build your own media controller app with the new
+{@code android.media.session.MediaController} class, which provides
+simplified transport controls APIs that replace those in
+{@code android.media.RemoteControlClient}. The {@code MediaController} class
+allows thread-safe control of playback from a non UI process, making it easier
+to control your media playback service from your app’s user interface.
+
+<p>You can also create multiple controllers to send playback commands,
+media keys, and other events to the same ongoing
+{@code android.media.session.MediaSession}. When you add a controller, you must
+call {@code MediaSession.getSessionToken()} to request an access
+token in order for your app to interact with the session.</p>
+
+<p>Send transport commands such as "play", "stop", "skip", and
+"set rating" by using {@code MediaController.TransportControls}. To handle
+in-bound media transport commands from controllers attached to the session, you
+should override the callback methods in
+{@code MediaSession.TransportControlsCallback}.</p>
+
+<p>You can also create rich notifications that allow playback control tied to a
+media session with the new {@code android.app.Notification.MediaStyle} class.</p>
+
+<h2 id="Storage">Storage</h2>
+
+<h3 id="DirectorySelection">Directory selection</h3>
+
+<p>The L Developer Preview extends the <a href="{@docRoot}guide/topics/providers/document-provider.html">Storage Access Framework</a> to let users
+select an entire directory, rather than individual files, to give your app
+read/write access to media files. When a directory is selected, your app also
+has access to all its child directories and content.</p>
+
+<p>To get the absolute paths to directories on external storage devices where
+applications can store media files, call the
+{@code android.content.Context.getExternalMediaDirs()} method. No additional
+permissions are needed by your app to read or write to the returned paths.
+External storage devices here are those considered by the system to be a
+permanent part of the device, and includes emulated external storage and
+physical media slots such as SD cards in battery compartments.</p>
+
+<p>If you want to access a document in an existing directory, call the
+{@code android.provider.DocumentsContract.buildDocumentViaUri()} method and pass
+in a Uri representing the path to the parent directory and the target document
+ID. The method returns a new {@link android.net.Uri} with which your app can
+use to write media content with {@code DocumentsContract.createDocument()}.
+
+<h2 id="Wireless">Wireless &amp; Connectivity</h2>
+
+<h3 id="Multinetwork">Dynamic network selection and seamless handoff</h3>
+<p>The L Developer Preview provides new multi-networking APIs for your app to
+dynamically scan for available networks with specific capabilities, and
+establish a connection to them. This is useful when your app requires a
+specialized network, such as an SUPL, MMS, or carrier-billing network, or if
+you want to send data using a particular type of transport protocol.</p>
+
+<p>To select and connect to a network dynamically from your app, first
+instantiate a {@code android.net.ConnectivityManager}. Next, create a
+{@code android.net.NetworkRequest} to specify the network features and transport
+type your app is interested in. To start scanning for suitable networks, call
+{@code ConnectivityManager.requestNetwork()} or
+{@code ConnectivityManager.registerNetworkCallback(), and pass in the
+{@code NetworkRequest} object and an implementation of
+{@code ConnectivityManager.NetworkCallbackListener}.</p>
+
+<p>When the system detects a suitable network, it connects to the network and
+invokes the {@code NetworkCallbackListener.onAvailable()} callback. You can use
+the {@code android.net.Network} object from the callback to get additional
+information about the network, or to establish a socket connection.</p>
+
+<h3 id="BluetoothBroadcasting">Bluetooth broadcasting</h3>
+<p>Android 4.3 introduced platform support for <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low Energy</a>
+(BLE) in the central role. In the L Developer Preview, an Android device can now
+act as a Bluetooth LE <em>peripheral device</em> and make its presence known to
+nearby devices. For instance, you can build apps that allow a device to
+function as a pedometer or health monitor and communicate its data with another
+BLE device.</p>
+
+<p>The new {@code android.bluetooth.le} APIs enable your apps to broadcast advertisements, scan for responses, and form connections with nearby BLE devices.
+You must add the {@code android.permission.BLUETOOTH_ADMIN} permission in your
+manifest in order for your app to use the new advertising and scanning features.</a>
+
+<p>To begin Bluetooth LE advertising so that other devices can discover the
+device running your app, call {@code android.bluetooth.le.BluetoothAdvertiser.startAdvisertising()} and pass in an implementation of the
+{@code android.bluetooth.le.AdvertiseCallback} class to report the success
+or failure of the advertising operation.</p>
+
+<p>Conversely, if you want to scan for Bluetooth LE devices nearby, call
+{@code android.bluetooth.le.BluetoothLeScanner.startScan()} and pass in an
+implementation of {@code android.bluetooth.le.ScanCallback} to report if a
+Bluetooth LE advertisement is found. Optionally, you can pass in filters to scan
+for a specific type of device.</p>
+
+<h3 id="NFCEnhancements">NFC enhancements</h3>
+<p>The L Developer Preview adds these enhancements to enable wider and more
+flexible use of NFC:</p>
+
+<ul>
+<li>Android Beam is now available in the share menu.
+<li>Support for the <a href="http://www.wi-fi.org/discover-wi-fi/wi-fi-direct">Wi-fi Direct standard</a>.
+<li>Your app can invoke the Android Beam on the user’s device to share data by
+calling {@code android.nfc.NfcAdapter.invokeBeam()}. This avoids the need for
+the user to manually tap the device against another NFC-capable device to
+complete the data transfer.
+<li>Use the new {@code android.nfc.NdefRecord.createTextRecord()} method if
+  you want to create an NDEF record containing UTF-8 text data.
+<li>If you are developing a payment app, you now have the ability to
+register an NFC application ID (AID) dynamically by calling
+{@code android.nfc.cardemulation.CardEmulation.registerAidsForService()}.
+You can also use {@code android.nfc.cardemulation.CardEmulation.setPreferredService()}
+to set the preferred card emulation service that should be used when a specific
+activity is in the foreground.
+</ul>
+
+<h2 id="Power">Power Efficiency</h2>
+
+<h3 id="JobScheduler">Scheduling jobs</h3>
+<p>The L Developer Preview provides a new {@code android.app.job.JobScheduler}
+API that lets you optimize battery life by defining jobs for the system to run
+asynchronously at a later time, such as when the device is charging. This is
+useful when you want to defer non user-facing units of work, have application
+code that accesses the network, or want to run a number of tasks as a batch on
+a regular schedule.</p>
+
+<p>A {@code android.app.job.JobInfo} object encapsulates such a unit of work,
+and provides an exact description of the criteria you are scheduling.</p>
+
+<p>Use the {@code android.app.job.JobInfo.Builder} to configure how the
+scheduled task should run. You can schedule the task to run under specific
+conditions such as only while the device is charging, when connected to an
+unmetered network, or when the system deems the device is idle.</p>
+
+<p>For example, you can add code like this to run your task on an
+unmetered network:</p>
+
+<pre>
+JobInfo uploadTask = new JobInfo.Builder(mJobId, mServiceComponent)
+        .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
+        .build();
+
+JobScheduler jobScheduler =
+        (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE)
+jobScheduler.schedule(uploadTask);
+</pre>
+
+<h3 id="PowerMeasurementTools">Developer tools and APIs for power measurement</h3>
+<p>The L Developer Preview provides several new developer tools and APIs to help
+you better measure and understand your app's power usage.</p>
+
+<dl>
+<dt><strong>batterystats</strong></dt>
+<dd>
+<p>The {@code dumpsys batterystats} command allows you to generate interesting
+statistical data about battery usage on a device, organized by unique user ID
+(UID). The statistics generated by the tool include:</p>
+
+<ul>
+<li>History of battery related events
+<li>Global statistics for the device
+<li>Approximated power use per UID and system component
+<li>Per-app mobile ms per packet
+<li>System UID aggregated statistics
+<li>App UID aggregated statistics
+</ul>
+
+<p>Use the {@code --help} option to learn about the various options for
+tailoring the output. For example, to run the tool to print battery usage
+statistics since the device was last charged for a given app package, run this
+command:
+<pre>
+$ adb shell dumpsys batterystats --charged <package-name>
+</pre>
+</dd>
+
+<dt><strong>Battery Historian</strong></dt>
+<dd>
+<p>The Battery Historian tool ({@code historian.par}) analyzes L-based Android
+bug reports and creates an HTML visualization of power-related events. It can
+also visualize power consumption data from a power monitor, and will attempt to
+map power usage to the wakelocks seen. You can find the Battery Historian tool
+in {@code &lt;sdk&gt;/tools}.</p>
+
+<p>For best results, you should first enable full wakelock reporting to allow
+the Battery Historian tool to monitor uninterrupted over an extended period of
+time:</p>
+<pre>
+$ adb shell dumpsys batterystats --enable full-wake-history
+</pre>
+
+<p>You should also reset battery statistics at the beginning of a
+measurement:</p>
+<pre>
+$ adb shell dumpsys batterystats --reset
+</pre>
+
+<p>To generate an HTML visualization:</p>
+<pre>
+$ historian.par [-p powerfile] bugreport.txt > out.html
+</pre>
+</dd>
+
+<dt><strong>On-device power management</strong></dt>
+<dd>
+<p>You can use the {@code android.os.BatteryManager} API to obtain power
+consumption information based on the battery fuel gauge included in Android
+phones and tablets. This is useful in cases when it is not convenient to
+connect external measurement equipment to the Android device.</p>
+<p>To retrieve the battery properties, call {@code BatteryManager.getIntProperty()}
+or {@code BatteryManager.getLongProperty()}. The properties available, the
+exact resolution of the values of each, and other characteristics such as
+update frequency depend on the particular device being tested.</p>
+
+<p>The following properties can be inspected on all Android devices:</p>
+
+<table>
+  <tr>
+     <th>Property</th>
+     <th>Description</th>
+  </tr>
+  <tr>
+     <td>{@code BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER}</td>
+     <td>Remaining battery capacity in microampere-hours.</td>
+  </tr>
+  <tr>
+     <td>{@code BatteryManager.BATTERY_PROPERTY_CURRENT_NOW}</td>
+     <td>Instantaneous battery current in microamperes.</td>
+  </tr>
+  <tr>
+     <td>{@code BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE}</td>
+     <td>Average battery current in microamperes</td>
+  </tr>
+  <tr>
+     <td>{@code BatteryManager.BATTERY_PROPERTY_CAPACITY}</td>
+     <td>Remaining battery capacity as an integer percentage.</td>
+  </tr>
+  <tr>
+     <td>{@code BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER}</td>
+     <td>Remaining energy in nanowatt-hours.</td>
+  </tr>
+</table>
+<dd>
+</dl>
+
+<h2 id="Enterprise">Enterprise</h2>
+<h3 id="ManagedProvisioning">Managed provisioning</h3>
+
+<p>The L Developer Preview provides new functionality for running apps within
+an enterprise environment:</p>
+<ul>
+<li><strong>Create managed user profiles</strong>. A device administrator can
+initiate a managed provisioning process to enroll a user device with an
+existing personal account into a co-present but separate managed profile that
+the administrator controls.
+<li><strong>Set device owner scope</strong>. Device administrators can also
+apply managed provisioning to configure a device that has no previous user
+accounts installed, so that they have full control over the device.
+</ul>
+
+<p>To start the manged provisioning process, send
+{@code ACTION_PROVISION_MANAGED_PROFILE} in an {@link android.content.Intent}. A
+user may be associated with more than one managed profile. To get a list of the
+managed profiles associated with the user, call
+{@code android.os.UserManager.getUserProfiles()}.</p>
+
+<p>Once a managed profile is created for a user, apps that are managed by the
+device administrator will appear alongside non-managed apps in the user’s
+Launcher, Recent apps screen, and notifications. A device policy management app
+can make the managed apps visually prominent by appending a “work” badge to the
+icon drawable with {@code android.os.UserManager.getBadgeDrawableForUser()}.</p>
+
+<p>If you are developing a Launcher app, you can use the new {@code android.content.pm.LauncherApps} class to get a list of launchable activities for the current user
+and any associated managed profiles.</p>
+
+<h2 id="Printing">Printing Framework</h2>
+
+<h3 id="PDFRender">Render PDF as bitmap</h3>
+<p>You can now render PDF document pages into bitmap images for printing by
+using the new {@code android.graphics.pdf.PdfRenderer} class. You must specify a
+{@code ParcelFileDescriptor} that is seekable (that is, the file can be randomly
+accessed) on which the system writes the the printable content. Your app can
+obtain a page for rendering with {@code openPage()}, then call {@code render()}
+to turn the opened {@code PdfRenderer.Page} into a bitmap. You can also set
+additional parameters if you only wan to convert a portion of the document into
+a bitmap image (for example, to implement <a href="http://en.wikipedia.org/wiki/Tiled_rendering">tile rendering</a> in order to zoom in on the document).</p>
+
+<h2 id="TestingA11y">Testing &amp; Accessibility </h2>
+
+<h3 id="Testing A11yImprovements">Testing and accessibility improvements</h3>
+<p>The L Developer Preview adds the following support for testing and
+accessibility:</p>
+
+<ul>
+<li>You can use the new {@code android.app.UiAutomation.getWindowAnimationFrameStats()}
+and {@code android.app.UiAutomation.getWindowContentFrameStats()} methods to
+capture frame statistics for window animations and content. This lets you
+write instrumentation tests to evaluate if the app under test is rendering
+frames at a sufficient refresh frequency to provide a smooth user experience.
+<li>You can execute shell commands from your instrumentation test with the new
+{@code android.app.UiAutomation.executeShellCommand()}. The command execution
+is similar to running 'adb shell' from a host connected to the device. This
+allows you to use shell based tools such as {@code dumpsys}, {@code am},
+{@code content}, and {@code pm}.
+<li>Accessibility services and test tools that use the accessibility APIs
+(such as <a href="{@docRoot}tools/help/uiautomator/index.html">UiAutomator</a>)
+can now retrieve detailed information about the properties of windows on the
+screen that sighted users can interact with. To retrieve a list of
+{@code android.view.accessibility.AccessibilityWindowInfo} representing the
+windows information, call the new
+{@code android.accessibilityservice.AccessibilityService.getWindows()} method.
+<li>You can use the new {@code android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction} to define standard or customized
+actions to perform on an {@code android.view.accessibility.AccessibilityNodeInfo}.
+The new {@code AccessibilityAction} class replaces the actions-related APIs
+previously found in {@code AccessibilityNodeInfo}.
+</ul>
+
+<h2 id="manifest">Manifest Declarations</h2>
+
+<h3 id="ManifestFeatures">Declarable required features</h3>
+<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a> element so you
+can ensure that your app is installed only on devices that provide the features
+your app needs.</p>
+
+<ul>
+<li>{@code FEATURE_LEANBACK}. Declares that your app must be installed only on devices that support the <a href="{@docRoot}tv}">Android TV</a> user interface. Example:
+<pre>
+&lt;uses-feature android:name="android.software.leanback"
+              android:required="true" /&gt;
+</pre>
+
+<li>{@code FEATURE_MANAGEDPROFILES}. Declares that your app must only be installed on devices that support managed profiles for enterprise users. Example:
+<pre>
+&lt;uses-feature android:name="android.software.managedprofiles"
+              android:required="true" /&gt;
+</pre>
+<li>{@code FEATURE_WEBVIEW}. Declares that your app must only be installed on devices that fully implement the android.webkit.* APIs. Example:
+<pre>
+&lt;uses-feature android:name="android.software.webview"
+              android:required="true" /&gt;
+</pre>
+</ul>
+
+<h3 id="ManifestPermissions">User permissions</h3>
+<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code &lt;uses-permission&gt;}</a> to declare the
+permissions your app requires in order to access certain APIs.
+
+<ul>
+<li>{@code SIM_COMMUNICATION}. Required to communicate with a SIM card using
+  logical channels.
+</ul>
diff --git a/docs/html/preview/images/android.png b/docs/html/preview/images/android.png
new file mode 100644
index 0000000..3aeaa98
--- /dev/null
+++ b/docs/html/preview/images/android.png
Binary files differ
diff --git a/docs/html/preview/images/art.png b/docs/html/preview/images/art.png
new file mode 100644
index 0000000..c48f039
--- /dev/null
+++ b/docs/html/preview/images/art.png
Binary files differ
diff --git a/docs/html/preview/images/bugs.png b/docs/html/preview/images/bugs.png
new file mode 100644
index 0000000..46adf05
--- /dev/null
+++ b/docs/html/preview/images/bugs.png
Binary files differ
diff --git a/docs/html/preview/images/hero.jpg b/docs/html/preview/images/hero.jpg
new file mode 100644
index 0000000..1c52989
--- /dev/null
+++ b/docs/html/preview/images/hero.jpg
Binary files differ
diff --git a/docs/html/preview/images/material.png b/docs/html/preview/images/material.png
new file mode 100644
index 0000000..2d807d4
--- /dev/null
+++ b/docs/html/preview/images/material.png
Binary files differ
diff --git a/docs/html/preview/images/notifications.png b/docs/html/preview/images/notifications.png
new file mode 100644
index 0000000..2fb2fea
--- /dev/null
+++ b/docs/html/preview/images/notifications.png
Binary files differ
diff --git a/docs/html/preview/images/updates.png b/docs/html/preview/images/updates.png
new file mode 100644
index 0000000..f165c5a
--- /dev/null
+++ b/docs/html/preview/images/updates.png
Binary files differ
diff --git a/docs/html/preview/images/volta.png b/docs/html/preview/images/volta.png
new file mode 100644
index 0000000..9125081
--- /dev/null
+++ b/docs/html/preview/images/volta.png
Binary files differ
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
new file mode 100644
index 0000000..e44e9f3
--- /dev/null
+++ b/docs/html/preview/index.jd
@@ -0,0 +1,236 @@
+page.title=Android L Developer Preview
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.type=about
+page.metaDescription=Test and build your apps against the next version of Android to ensure they're ready when the platform officially launches.
+page.image={@docRoot}preview/images/hero.jpg
+@jd:body
+
+<style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+  display:none;
+}
+</style>
+
+<style>
+#footer {
+    display: none;
+}
+.content-footer {
+  display: none;
+}
+</style>
+
+<div class="landing-body-content">
+  <div class="landing-hero-container">
+    <div class="landing-section preview-hero">
+      <div class="landing-hero-scrim"></div>
+      <div class="landing-hero-wrap">
+        <div class="vertical-center-outer">
+          <div class="vertical-center-inner">
+
+            <div class="col-12">
+              <div class="landing-section-header">
+
+                <div class="landing-h1 hero">L Developer Preview</div>
+                <div class="landing-subhead hero">
+                <p>An early look at the next release</p>
+                </div>
+              <div class="landing-hero-description">
+               <p>Test and build your apps against the next<br />
+              version of Android to ensure they're ready<br/>
+              when the platform officially launches.</p>
+              </div>
+
+              <div class="landing-body">
+                <a href="/preview/setup-sdk.html" class="landing-button landing-primary" style="margin-top: 40px;">
+                  Get Started
+                </a>
+              </div>
+            </div>
+
+          </div>
+        </div>
+      </div> <!-- end .wrap -->
+      <div class="landing-scroll-down-affordance">
+        <a class="landing-down-arrow" href="#extending-android-to-landingables">
+          <img src="/wear/images/carrot.png" alt="Scroll down to read more">
+        </a>
+      </div>
+    </div> <!-- end .landing-section .landing-hero -->
+  </div> <!-- end .landing-hero-container -->
+
+
+    <div class="landing-rest-of-page">
+      <div class="landing-section" id="extending-android-to-landingables">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">See What's New</div>
+            <div class="landing-subhead">
+              Take advantage of all the new capabilities, which are focused on design and performance.
+            </div>
+          </div>
+
+          <div class="landing-body">
+
+            <div class="landing-breakout cols">
+              <div class="col-4">
+                <img src="/preview/images/material.png" style="opacity:.6" alt="">
+                <p>A New UI Design</p>
+                <p class="landing-small">
+                  Create a consistent experience across mobile and the web with
+                   material design, the new Google-wide standard.
+                </p>
+                <p class="landing-small">
+                  <a href="/preview/material/index.html">Learn about material</a>
+                </p>
+              </div>
+              <div class="col-4">
+                <img src="/preview/images/art.png" alt="">
+                <p>A Rehauled Runtime</p>
+                <p class="landing-small">
+                  Test your apps and get them ready for <b>ART</b> (<b>A</b>ndroid <b>R</b>un<b>t</b>ime),
+                  the default runtime in the next release.
+
+                </p>
+                <p class="landing-small">
+                  <a href="/preview/api-overview.html#ART">Learn about ART</a>
+                </p>
+              </div>
+              <div class="col-4">
+                <img src="/preview/images/notifications.png" alt="">
+                <p style="width:230px">Enhanced Notifications</p>
+                <p class="landing-small">
+                   Get more control over where notifications appear,
+                   how they look, and automatic syncing to non-handheld devices.
+                </p>
+                <p class="landing-small">
+                  <a href="/preview/api-overview.html#UI">Learn more</a>
+                </p>
+              </div>
+              <div class="col-4">
+                <img src="/preview/images/volta.png" alt="">
+                <p>Project Volta</p>
+                <p class="landing-small">
+                  We've tuned the platform to be more energy efficient and
+                  to give you more control over resource usage.
+                </p>
+                <p class="landing-small">
+                  <a href="/preview/api-overview.html#Power">Learn more</a>
+                </p>
+              </div>
+            </div>
+              <p>See the <a href="{@docRoot}preview/api-overview.html">API overview</a> for more information
+              on the rest of the new and updated features.</p>
+          </div>
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+
+
+      <div class="landing-section landing-gray-background">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Get Your Apps Ready</div>
+            <div class="landing-subhead">
+              <p>We're giving you an early look at the SDK, so you can test your apps and build in new features.</p>
+            </div>
+          </div>
+          <div class="landing-body">
+             <p>You'll get the system images for the Nexus 5, Nexus 7 (v2),
+             and the emulator to take the new platform for a spin. In addition, you'll have
+             access to all the APIs with a preview build of the SDK.
+            </p>
+
+            <p>Check out the getting started, developer guides, and reference documentation
+            for all the information you need to get up and running.</p>
+
+            <a href="/preview/setup-sdk.html" class="landing-button landing-secondary" style="margin-top: 20px;">
+              Get Started
+            </a>
+          </div>
+        </div>
+      </div>
+    <div class="landing-section">
+        <div class="wrap">
+          <div class="cols">
+            <div class="landing-body">
+              <div class="col-3-wide">
+                  <a target="_blank" href="http://submit-bugs!">
+                    <img class="landing-social-image" src="{@docRoot}preview/images/bugs.png" alt="">
+                  </a>
+                <div class="landing-social-copy">
+                  <p>Issue Tracker</p>
+                  <p class="landing-small">
+                  Let us know when you encounter problems, so we can fix them and make
+                  the platform better for you and your users.
+                    </p><p class="landing-small">
+                      <a target="_blank" href="http://submit-bugs!">
+                      Report Issues</a>
+                    </p>
+                  <p></p>
+                </div>
+              </div>
+              <div class="col-3-wide">
+                <a target="_blank" href="http://plus.google.com">
+                  <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="">
+                </a>
+                <div class="landing-social-copy">
+                  <p>Google+ </p>
+                  <p class="landing-small">
+                    Join the community of Android developers testing out the L Developer Preview and
+                    share your thoughts and experiences.
+                  </p><p class="landing-small">
+                    <a target="_blank" href="http://plus.google.com">
+                    Discuss on Google+</a>
+                    </p>
+                </div>
+              </div>
+              <div class="col-3-wide">
+                <a target="_blank" href="{@docRoot}preview/release-notes.html">
+                  <img class="landing-social-image" src="{@docRoot}preview/images/updates.png" alt="">
+                </a>
+                <div class="landing-social-copy">
+                  <p>Support and Updates</p>
+                  <p class="landing-small">
+                  Updates to the L Developer Preview are delivered
+                  in the Android SDK Manager. Check back periodically
+                  for news about the changes.
+                  </p>
+                  <p class="landing-small">
+                    <a target="_blank" href="{@docRoot}preview/support.html">Get Support</a>
+                  </p>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div> <!-- end .wrap -->
+      </div>
+
+    <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
+      <div class="layout-content-col col-16" style="padding-top:4px">
+        <style>#___plusone_0 {float:right !important;}</style>
+        <div class="g-plusone" data-size="medium"></div>
+      </div>
+    </div>
+    <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+      <div id="copyright">
+        Except as noted, this content is
+        licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+        Creative Commons Attribution 2.5</a>. For details and
+        restrictions, see the <a href="/license.html">Content
+        License</a>.
+      </div>
+    </div>
+  </div> <!-- end landing-body-content -->
+
+  <script>
+  $("a.landing-down-arrow").on("click", function(e) {
+    $("body").animate({
+      scrollTop: $(".preview-hero").height() + 76
+    }, 1000, "easeOutQuint");
+    e.preventDefault();
+  });
+  </script>
\ No newline at end of file
diff --git a/docs/html/preview/material/animations.jd b/docs/html/preview/material/animations.jd
new file mode 100644
index 0000000..cee782a
--- /dev/null
+++ b/docs/html/preview/material/animations.jd
@@ -0,0 +1,378 @@
+page.title=Animations
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#touch">Touch Feedback</a></li>
+  <li><a href="#reveal">Reveal Effect</a></li>
+  <li><a href="#transitions">Activity Transitions</a></li>
+  <li><a href="#curvedmotion">Curved Motion</a></li>
+  <li><a href="#viewstate">View State Changes</a></li>
+  <li><a href="#drawabletint">Drawable Tinting</a></li>
+</ol>
+</div>
+</div>
+
+<p>Animations in material design give users feedback on their actions and provide visual
+continuity as users interact with your app. The material theme provides some default animations
+for buttons and activity transitions, and the Android L Developer Preview provides additional
+APIs that let you customize these animations and create new ones:</p>
+
+<ul>
+<li>Touch feedback</li>
+<li>Reveal effect</li>
+<li>Activity transitions</li>
+<li>Curved motion</li>
+<li>View state changes</li>
+</ul>
+
+
+<h2 id="touch">Touch Feedback</h2>
+
+<p>In the Android L Developer Preview the default touch feedback animations for buttons use the new
+<code>RippleDrawable</code> class, which transitions between different states with a ripple
+effect.</p>
+
+<p>To use this functionality in your custom views, create a <code>RippleDrawable</code> and set
+it as the background of your view. You can define a <code>RippleDrawable</code> as an XML resource
+using the <code>ripple</code> element.</p>
+
+
+<h2 id="reveal">Reveal Effect</h2>
+
+<p>The <code>View.createRevealAnimator</code> method enables you to animate a clipping circle
+to reveal or hide a view.</p>
+
+<p>To reveal a previously invisible view using this effect:</p>
+
+<pre>
+// previously invisible view
+View myView = findViewById(R.id.my_view);
+
+// get the center for the clipping circle
+int cx = (myView.getLeft() + myView.getRight()) / 2;
+int cy = (myView.getTop() + myView.getBottom()) / 2;
+
+// get the final radius for the clipping circle
+int finalRadius = myView.getWidth();
+
+// create and start the animator for this view
+// (the start radius is zero)
+ValueAnimator anim = myView.createRevealAnimator(cx, cy, 0, finalRadius);
+anim.start();
+</pre>
+
+<p>To hide a previously visible view using this effect:</p>
+
+<pre>
+// previously visible view
+final View myView = findViewById(R.id.my_view);
+
+// get the center for the clipping circle
+int cx = (myView.getLeft() + myView.getRight()) / 2;
+int cy = (myView.getTop() + myView.getBottom()) / 2;
+
+// get the initial radius for the clipping circle
+int initialRadius = myView.getWidth();
+
+// create the animation (the final radius is zero)
+ValueAnimator anim = myView.createRevealAnimator(cx, cy, initialRadius, 0);
+
+// make the view invisible when the animation is done
+anim.addListener(new AnimatorListenerAdapter() {
+    &#64;Override
+    public void onAnimationEnd(Animator animation) {
+        super.onAnimationEnd(animation);
+        myView.setVisibility(View.INVISIBLE);
+    }
+});
+
+// start the animation
+anim.start();
+</pre>
+
+
+<h2 id="transitions">Activity Transitions</h2>
+
+<p>The Android L Developer Preview enables your app to customize the default animations for
+activity transitions. You can specify custom animations for enter and exit transitions and for
+transitions of shared elements between activities.</p>
+
+<ul>
+  <li>An <strong>enter</strong> transition determines how views in an activity enter the scene.
+  For example, in the <em>explode</em> enter transition the views enter the scene from outside
+  and fly in towards the center of the screen.</li>
+
+  <li>An <strong>exit</strong> transition determines how views in an activity exit the scene. For
+  example, in the <em>explode</em> exit transition the views exit the scene away from the
+  center.</li>
+
+  <li>A <strong>shared elements</strong> transition determines how views that are shared between
+  two activities transition between these activities. For example, if two activities have the same
+  image in different positions and sizes, the <em>moveImage</em> shared element transition
+  translates and scales the image smoothly between these activities.</li>
+</ul>
+
+<img src="/preview/material/images/SceneTransition.png" alt=""
+     id="figure1" style="width:600px;margin-top:20px"/>
+<p class="img-caption">
+  <strong>Figure 1</strong> - A scene transition with one shared element.
+</p>
+
+<h3>Specify custom transitions</h3>
+
+<p>First, enable window content transitions with the <code>android:windowContentTransitions</code>
+attribute when you define a style that inherits from the material theme:</p>
+
+<pre>
+&lt;style name="BaseAppTheme" parent="android:Theme.Material">
+  &lt;!-- enable window content transitions -->
+  &lt;item name="android:windowContentTransitions">true&lt;/item>
+
+  &lt;!-- specify enter and exit transitions -->
+  &lt;item name="android:windowEnterTransition">@transition/explode&lt;/item>
+  &lt;item name="android:windowExitTransition">@transition/explode&lt;/item>
+
+  &lt;!-- specify shared element transitions -->
+  &lt;item name="android:windowSharedElementEnterTransition">
+    &#64;transition/move_image&lt;/item>
+  &lt;item name="android:windowSharedElementExitTransition">
+    &#64;transition/move_image&lt;/item>
+&lt;/style>
+</pre>
+
+<p>You can also specify enter, exit, and shared element transitions in your style definition.
+The <code>move_image</code> transition in this example is defined as follows:</p>
+
+<pre>
+&lt;!-- res/transition/move_image.xml -->
+&lt;!-- (see also Shared Transitions below) -->
+&lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+  &lt;moveImage>
+    &lt;targets>
+      &lt;!-- shared view in the first activity -->
+      &lt;target android:targetId="@id/image_small" />
+      &lt;!-- shared view in the second activity -->
+      &lt;target android:targetId="@id/image_big" />
+    &lt;/targets>
+  &lt;/moveImage>
+&lt;/transitionSet>
+</pre>
+
+<p>The <code>moveImage</code> element corresponds to the <code>android.transition.MoveImage</code>
+class. For more information, see the API reference for <code>android.transition.Transition</code>.
+</p>
+
+<p>To enable window content transitions in your code instead, call the
+<code>Window.requestFeature</code> method:</p>
+
+<pre>
+// inside your activity
+getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+
+// set an exit transition
+getWindow().setExitTransition(new Explode());
+</pre>
+
+<p>To specify transitions in your code, call these methods with a <code>Transition</code>
+object:</p>
+
+<ul>
+  <li><code>Window.setEnterTransition</code></li>
+  <li><code>Window.setExitTransition</code></li>
+  <li><code>Window.setSharedElementEnterTransition</code></li>
+  <li><code>Window.setSharedElementExitTransition</code></li>
+</ul>
+
+<h3>Start an activity using transitions</h3>
+
+<p>If you enable transitions and set an exit transition for an activity, the transition is activated
+when you launch another activity with the <code>startActivity</code> method. If you have set an
+enter transition for the second activity, the transition is also activated when the activity
+starts.</p>
+
+<h3>Shared elements transitions</h3>
+
+<p>To make a screne transition animation between two activities that have a shared element:</p>
+
+<ol>
+<li>Enable window content transitions in your style.</li>
+<li>Specify a shared elements transition in your style.</li>
+<li>Define your transition as an XML resource specifying the IDs of the target views.</li>
+<li>Assign a common name to the shared elements in both layouts with the
+    <code>android:viewName</code> attribute.</li>
+<li>Use the <code>ActivityOptions.makeSceneTransitionAnimation</code> method.</li>
+</ol>
+
+<pre>
+// get the element that receives the click event
+final View imgContainerView = findViewById(R.id.img_container);
+
+// get the common element for the transition in this activity
+final View androidRobotView = findViewById(R.id.android_robot_img);
+
+// define a click listener
+imgContainerView.setOnClickListener(new View.OnClickListener() {
+    &#64;Override
+    public void onClick(View view) {
+        Intent intent = new Intent(this, Activity2.class);
+        // create the transition animation - the images in the layouts
+        // of both activities are defined with android:viewName="robot"
+        ActivityOptions options = ActivityOptions
+            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
+        // start the new activity
+        startActivity(intent, options.toBundle());
+    }
+});
+</pre>
+
+<p>For shared dynamic views that you generate in your code, use the <code>View.setViewName</code>
+method to specify a common element name in both activities.</p>
+
+<h3>Multiple shared elements</h3>
+
+<p>To make a scene transition animation between two activities that have more than one shared
+element, define the shared elements in both layouts with the <code>android:viewName</code>
+attribute (or use the <code>View.setViewName</code> in both activities), and create an
+<code>ActivityOptions</code> object as follows:</p>
+
+<pre>
+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
+    new Pair[] {
+        Pair.create(view1, "agreedName1"),
+        Pair.create(view2, "agreedName2"),
+        ...
+    }
+);
+</pre>
+
+
+<h2 id="curvedmotion">Curved Motion</h2>
+
+<p>Animations in material design rely on curves for time interpolation and spatial movement
+patterns. The Android L Developer Preview provides new APIs that enable you to define custom
+timing curves and curved motion patterns for animations.</p>
+
+<p>The <code>PathInterpolator</code> class is a new interpolator based on a Bézier curve or a
+<code>Path</code> object. This interpolator specifies a motion curve in a 1x1 square, with anchor
+points at (0,0) and (1,1) and control points as specified using the constructor arguments. You can
+also define a <code>PathInterpolator</code> as an XML resource:</p>
+
+<pre>
+&lt;pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:controlX1="0.4"
+    android:controlY1="0"
+    android:controlX2="1"
+    android:controlY2="1"/>
+</pre>
+
+<p>The Android L Developer Preview provides XML resources for the three basic curves in the
+material design specification:</p>
+
+<ul>
+  <li><code>&#64;interpolator/fast_out_linear_in.xml</code></li>
+  <li><code>&#64;interpolator/fast_out_slow_in.xml</code></li>
+  <li><code>&#64;interpolator/linear_out_slow_in.xml</code></li>
+</ul>
+
+<p>You can pass a <code>PathInterpolator</code> object to the
+<code>Animation.setInterpolation</code> method.</p>
+
+<p>The <code>ObjectAnimator</code> class has new constructors that enable you to animate
+coordinates along a path using two or more properties at once. For example, the following animator
+uses a <code>Path</code> object to animate the X and Y properties of a view:</p>
+
+<pre>
+ObjectAnimator mAnimator;
+mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
+...
+mAnimator.start();
+</pre>
+
+
+<h2 id="viewstate">View State Changes</h2>
+
+<p>The new <code>StateListAnimator</code> class lets you define animators that run when the state
+of a view changes. The following example shows how to define an <code>StateListAnimator</code> as
+an XML resource:</p>
+
+<pre>
+&lt;!-- animate the elevation property of a view when pressed -->
+&lt;selector xmlns:android="http://schemas.android.com/apk/res/android">
+  &lt;item android:state_pressed="true">
+    &lt;set>
+      &lt;objectAnimator android:propertyName="elevation"
+        android:duration="100"
+        android:valueTo="60"
+        android:valueType="floatType"/>
+        &lt;!-- you could have other objectAnimator elements
+             here for "x" and "y", or other properties -->
+    &lt;/set>
+  &lt;/item>
+  &lt;item android:state_enabled="true"
+    android:state_pressed="false"
+    android:state_focused="true">
+    &lt;set>
+      &lt;objectAnimator android:propertyName="elevation"
+        android:duration="100"
+        android:valueTo="10"
+        android:valueType="floatType"/>
+    &lt;/set>
+  &lt;/item>
+&lt;/selector>
+</pre>
+
+<p>The new <code>AnimatedStateListDrawable</code> class lets you create drawables that show
+animations between state changes of the associated view. Some of the system widgets in the
+Android L Developer Preview use these animations by default. The following example shows how
+to define an <code>AnimatedStateListDrawable</code> as an XML resource:</p>
+
+<pre>
+&lt;!-- res/drawable/myanimstatedrawable.xml -->
+&lt;animated-selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    &lt;!-- provide a different drawable for each state-->
+    &lt;item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
+        android:state-pressed="true"/>
+    &lt;item android:id="@+id/focused" android:drawable="@drawable/drawableF"
+        android:state-focused="true"/>
+    &lt;item android:id="@id/default"
+        android:drawable="@drawable/drawableD"/>
+
+    &lt;!-- specify a transition -->
+    &lt;transition android:fromId="@+id/default" android:toId="@+id/pressed">
+        &lt;animation-list>
+            &lt;item android:duration="15" android:drawable="@drawable/dt1"/>
+            &lt;item android:duration="15" android:drawable="@drawable/dt2"/>
+            ...
+        &lt;/animation-list>
+    &lt;/transition>
+    ...
+&lt;/animated-selector>
+</pre>
+
+
+<h2 id="drawabletint">Drawable Tinting</h2>
+
+<p>The Android L Developer Preview enables you to define bitmaps as an alpha mask and to tint
+them using a color resource or a theme attribute that resolves to a color resource. You can
+create these assets only once and color them automatically to match your theme.</p>
+
+<p>To apply a tint to a bitmap in your code, use the <code>setTint</code> method in these
+classes:</p>
+
+<ul>
+<li><code>PaintDrawable</code></li>
+<li><code>NinePatchDrawable</code></li>
+<li><code>RippleDrawable</code></li>
+</ul>
+
+<p>In your layouts, use the <code>android:tint</code> attribute instead.</p>
+
+<p>The <code>setTint</code> method also lets you set the tint blending mode for
+<code>NinePatchDrawable</code> and <code>RippleDrawable</code> objects in your code. To set the
+tint mode in your layouts, use the <code>android:tintMode</code> attribute.</p>
diff --git a/docs/html/preview/material/compatibility.jd b/docs/html/preview/material/compatibility.jd
new file mode 100644
index 0000000..ce04e9e
--- /dev/null
+++ b/docs/html/preview/material/compatibility.jd
@@ -0,0 +1,63 @@
+page.title=Compatibility
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#materialtheme">Material Theme</a></li>
+  <li><a href="#layouts">Layouts</a></li>
+  <li><a href="#widgets">UI Widgets</a></li>
+  <li><a href="#animation">Animation APIs</a></li>
+</ol>
+</div>
+</div>
+
+<p>The new material design features (like the material theme and custom animations) are only
+available in the Android L Developer Preview. However, you can design your apps to make use of
+these features when running on devices with the Android L Developer Preview and still be
+compatible with previous releases of Android.</p>
+
+
+<h2 id="materialtheme">Material Theme</h2>
+
+<p>The material theme is only available in the Android L Developer Preview. To configure your
+app to use the material theme on devices running the Android L Developer Preview and an older
+theme on devices running earlier versions of Android:</p>
+
+<ol>
+<li>Define a theme that inherits from an older theme (like Holo) in
+<code>res/values/styles.xml</code>.</li>
+<li>Define a theme with the same name that inherits from the material theme in
+<code>res/values-v21/styles.xml</code>.</li>
+<li>Set this theme as your app's theme in the manifest file.</li>
+</ol>
+
+<p class="note"><strong>Note:</strong> If you do not provide an alternative theme in this manner,
+your app will not run on earlier versions of Android.</p>
+
+
+<h2 id="layouts">Layouts</h2>
+
+<p>If the layouts that you design according to the material design guidelines do not use any
+of the new XML attributes from the Android L Developer Preview, they will work on previous
+versions of Android. Otherwise, you can provide alternative layouts. You can also provide
+alternative layouts to customize how your app looks on earlier versions of Android.</p>
+
+<p>Create your layout files for the Android L Developer Preview inside <code>res/layout-v21/</code>
+and your alternative layout files for earlier versions of Android inside <code>res/layout/</code>.
+Alternative layouts have the same file name.</p>
+
+
+<h2 id="widgets">UI Widgets</h2>
+
+<p>The <code>RecyclerView</code> and <code>CardView</code> widgets are included in the Android L
+Developer Preview Support Library, so they are available in earlier versions of Android.</p>
+
+
+<h2 id="animation">Animation APIs</h2>
+
+<p>The new APIs for custom animations are only available in the Android L Developer Preview. To
+preserve compatibility with earlier verisons of Android, check the system version at runtime before
+you invoke these APIs.</p>
\ No newline at end of file
diff --git a/docs/html/preview/material/get-started.jd b/docs/html/preview/material/get-started.jd
new file mode 100644
index 0000000..9c0e55d
--- /dev/null
+++ b/docs/html/preview/material/get-started.jd
@@ -0,0 +1,146 @@
+page.title=Get Started
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#applytheme">Apply the Material Theme</a></li>
+  <li><a href="#layouts">Design Your Layouts</a></li>
+  <li><a href="#depth">Specify Depth in Your Views</a></li>
+  <li><a href="#widgets">Use the New UI Widgets</a></li>
+  <li><a href="#apis">Use the New APIs</a></li>
+</ol>
+</div>
+</div>
+
+<p>To create apps with material design:</p>
+
+<ol>
+  <li style="margin-bottom:10px">
+    Take a look at the <a href="">material design specification</a>.</li>
+  <li style="margin-bottom:10px">
+    Apply the material <strong>theme</strong> to your app.</li>
+  <li style="margin-bottom:10px">
+    Define additional <strong>styles</strong> to customize the material theme.</li>
+  <li style="margin-bottom:10px">
+    Create your <strong>layouts</strong> following material design guidelines.</li>
+  <li style="margin-bottom:10px">
+    Specify the <strong>depth</strong> for views to cast appropriate shadows.</li>
+  <li style="margin-bottom:10px">
+    Use the new <strong>widgets</strong> for complex views, such as lists and cards.</li>
+  <li style="margin-bottom:10px">
+    Use the new <strong>APIs</strong> to customize the animations in your app.</li>
+</ol>
+
+<h3>Update Your App for the Android L Developer Preview</h3>
+
+<p>To update an existing app for the Android L Developer Preview, design new layouts following
+material design guidelines and consider how you can improve the user experience for your app by
+incorporating depth, touch feedback and animations in your UI.</p>
+
+<h3>Create New Apps for the Android L Developer Preview</h3>
+
+<p>If you are creating a new app for the Android L Developer Preview, the material design
+guidelines provide you with a solid design framework for your app. Follow these guidelines and
+use the new functionality in the Android framework to design and develop your app.</p>
+
+
+<h2 id="applytheme">Apply the Material Theme</h2>
+
+<p>To apply the material theme in your app, specify a style that inherits from
+<code>android:theme.Material</code>:</p>
+
+<pre>
+&lt;!-- res/values/styles.xml -->
+&lt;resources>
+  &lt!-- your app's theme inherits from the Material theme -->
+  &lt;style name="AppTheme" parent="android:Theme.Material">
+    &lt!-- theme customizations -->
+  &lt;/style>
+&lt;/resources>
+</pre>
+
+<p>The material theme provides new system widgets that let you set their color palette and default
+animations for touch feedback and activity transitions. For more details, see
+<a href="{@docRoot}preview/material/theme.html">Material Theme</a>.</p>
+
+
+<h2 id="layouts">Design Your Layouts</h2>
+
+<p>In addition to applying and customizing the material theme, your layouts should conform to
+the material design guidelines. When you design your layouts, pay special attention to the
+following:</p>
+
+<ul>
+<li>Baseline grids</li>
+<li>Keylines</li>
+<li>Spacing</li>
+<li>Touch target size</li>
+<li>Layout structure</li>
+</ul>
+
+<p>You still define layouts inside XML files using the standard tools from the Android framework.
+For details on the material design guidelines, see the <a href="">material design
+specification</a>.</p>
+
+
+<h2 id="depth">Specify Depth in Your Views</h2>
+
+<p>In the Android L Developer Preview, views can cast shadows. The elevation value of a view
+determines the size of its shadow. To set the elevation of a view, use the
+<code>android:elevation</code> attribute in your layouts:</p>
+
+<pre>
+&lt;Button
+    android:id="@+id/my_button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/next"
+    <strong>android:elevation</strong>="10dp" />
+</pre>
+
+<p>For more details, see <a href="{@docRoot}preview/material/views-shadows.html">Views and
+Shadows</a>.</p>
+
+
+<h2 id="widgets">Use the New UI Widgets</h2>
+
+<p>The Android L Developer Preview includes two new UI widgets for complex views,
+<code>RecyclerView</code> and <code>CardView</code>. <code>RecyclerView</code> is a more advanced
+version of <code>ListView</code> that provides performance improvements and is easier to use.
+<code>CardView</code> lets you show pieces of information inside cards with a consistent look
+across apps. To include a <code>CardView</code> in your layout:</p>
+
+<pre>
+&lt;android.support.v7.widget.CardView
+    android:id="@+id/card_view"
+    android:layout_width="200dp"
+    android:layout_height="200dp"
+    card_view:cardCornerRadius="3dp">
+    ...
+&lt;/android.support.v7.widget.CardView>
+</pre>
+
+<p>For more information, see <a href="{@docRoot}preview/material/ui-widgets.html">UI Widgets</a>.</p>
+
+
+<h2 id="apis">Use the APIs to Customize Your Animations</h2>
+
+<p>The Android L Developer Preview includes new APIs to create custom animations in your app.
+For example, you can enable activity transitions and define an exit transition inside an
+activity:</p>
+
+<pre>
+// inside your activity
+getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+
+// set an exit transition
+getWindow().setExitTransition(new Explode());
+</pre>
+
+<p>When you start another activity from this activity, the exit transition is activated.</p>
+
+<p>To learn about all the features in the new APIs, see <a
+href="{@docRoot}preview/material/animations.html">Animations</a>.</p>
\ No newline at end of file
diff --git a/docs/html/preview/material/images/MaterialDark.png b/docs/html/preview/material/images/MaterialDark.png
new file mode 100644
index 0000000..6a72280
--- /dev/null
+++ b/docs/html/preview/material/images/MaterialDark.png
Binary files differ
diff --git a/docs/html/preview/material/images/MaterialLight.png b/docs/html/preview/material/images/MaterialLight.png
new file mode 100644
index 0000000..0e85528
--- /dev/null
+++ b/docs/html/preview/material/images/MaterialLight.png
Binary files differ
diff --git a/docs/html/preview/material/images/RecyclerView.png b/docs/html/preview/material/images/RecyclerView.png
new file mode 100644
index 0000000..364951d
--- /dev/null
+++ b/docs/html/preview/material/images/RecyclerView.png
Binary files differ
diff --git a/docs/html/preview/material/images/SceneTransition.png b/docs/html/preview/material/images/SceneTransition.png
new file mode 100644
index 0000000..ecaf472
--- /dev/null
+++ b/docs/html/preview/material/images/SceneTransition.png
Binary files differ
diff --git a/docs/html/preview/material/images/ThemeColors.png b/docs/html/preview/material/images/ThemeColors.png
new file mode 100644
index 0000000..bbcecf2
--- /dev/null
+++ b/docs/html/preview/material/images/ThemeColors.png
Binary files differ
diff --git a/docs/html/preview/material/images/card_travel.png b/docs/html/preview/material/images/card_travel.png
new file mode 100644
index 0000000..a804ca0
--- /dev/null
+++ b/docs/html/preview/material/images/card_travel.png
Binary files differ
diff --git a/docs/html/preview/material/images/list_mail.png b/docs/html/preview/material/images/list_mail.png
new file mode 100644
index 0000000..ca53ee1
--- /dev/null
+++ b/docs/html/preview/material/images/list_mail.png
Binary files differ
diff --git a/docs/html/preview/material/index.jd b/docs/html/preview/material/index.jd
new file mode 100644
index 0000000..b7abcb4
--- /dev/null
+++ b/docs/html/preview/material/index.jd
@@ -0,0 +1,117 @@
+page.title=Material Design
+page.type=design
+
+@jd:body
+
+<p itemprop="description">The Android L Developer Preview includes support for material design apps. Material design
+is a comprehensive guide for visual, motion, and interaction design across platforms and devices.
+To use material design in your Android apps, follow the guidelines defined in the
+<a href="">material design specification</a> and use the new components and functionality
+available in the Android L Developer Preview.</p>
+
+<p>The Android L Developer Preview provides the following elements for you to build material
+design apps:</p>
+
+<ul>
+  <li>A new theme</li>
+  <li>New widgets for complex views</li>
+  <li>New APIs for custom shadows and animations</li>
+</ul>
+
+
+<h3>Material Theme</h3>
+
+<p>The material theme provides a new style for your app, system widgets that let you set
+their color palette, and default animations for touch feedback and activity transitions.</p>
+
+<!-- two columns -->
+<div style="width:700px;margin-top:25px;margin-bottom:20px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+  <img src="{@docRoot}preview/material/images/MaterialDark.png" style="width:250px;"/>
+  <div style="width:140px;margin:0 auto">
+  <p style="margin-top:8px">Dark Material theme</p>
+  </div>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+  <img src="{@docRoot}preview/material/images/MaterialLight.png" style="width:250px;"/>
+  <div style="width:140px;margin:0 auto">
+  <p style="margin-top:8px">Light Material theme</p>
+  </div>
+</div>
+<br style="clear:left"/>
+</div>
+
+
+<h3>New Widgets</h3>
+
+<p>The Android L Developer Preview includes two new widgets for displaying complex views:</p>
+
+<!-- two columns -->
+<div style="width:700px;margin-top:25px;margin-bottom:20px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+  <img src="{@docRoot}preview/material/images/list_mail.png" style="width:250px;"/>
+  <p>The new <code>RecyclerView</code> widget is a more advanced version of <code>ListView</code>
+  provides performance improvements for dynamic views and is easier to use.</p>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+  <img src="{@docRoot}preview/material/images/card_travel.png" style="width:250px;"/>
+  <p>The new <code>CardView</code> widget lets you display important pieces of information inside
+  cards that have a consistent look and feel.</p>
+</div>
+<br style="clear:left"/>
+</div>
+
+
+<h3>View Shadows</h3>
+
+<p>In addition to the X and Y components, views in the Android L Developer Preview have a Z
+component. This new component represents the elevation of a view, which determines the size of
+its shadow: views with higher Z values cast bigger shadows.</p>
+
+<div style="width:290px;margin-left:35px;float:right">
+  <div class="framed-nexus5-port-span-5">
+  <video class="play-on-hover" autoplay>
+    <source src="/preview/material/videos/ContactsAnim.mp4"/>
+    <source src="/preview/material/videos/ContactsAnim.webm"/>
+    <source src="/preview/material/videos/ContactsAnim.ogv"/>
+  </video>
+  </div>
+  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
+    <em>Click on the device screen to replay the movie</em>
+  </div>
+</div>
+
+<h3>Animations</h3>
+
+<p>The Android L Developer Preview provides new APIs that let you create custom animations for
+touch feedback in UI controls, view state changes, and activity transitions.</p>
+
+<p>The new animation APIs in the Android L Developer Preview let you:</p>
+
+<ul>
+<li style="margin-bottom:15px">
+Respond to touch events in your views with <strong>touch feedback</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Hide and show views with <strong>reveal effect</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Switch between activities with custom <strong>activity transition</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Create custom animation patterns with <strong>curved motion</strong>.
+</li>
+<li style="margin-bottom:15px">
+Animate changes in one or more view properties with <strong>view state change</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Show animations in <strong>state list drawables</strong> between view state changes.
+</li>
+</ul>
+
+
+<h3>New Capabilities for Drawables</h3>
+
+<p>The Android L Developer Preview supports <strong>drawable tinting</strong>: you can define
+bitmaps as an alpha mask and tint them using a color resource. You can create these assets only
+once and color each instance to match your theme.</p>
diff --git a/docs/html/preview/material/theme.jd b/docs/html/preview/material/theme.jd
new file mode 100644
index 0000000..b954960
--- /dev/null
+++ b/docs/html/preview/material/theme.jd
@@ -0,0 +1,100 @@
+page.title=Material Theme
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#colorpalette">Customize the Colot Palette</a></li>
+  <li><a href="#statusbar">Customize the Status Bar</a></li>
+  <li><a href="#inheritance">Theme Inheritance</a></li>
+</ol>
+</div>
+</div>
+
+<p>The new material theme provides:</p>
+
+<ul>
+  <li>System widgets that let you set their color palette</li>
+  <li>Touch feedback animations for the system widgets</li>
+  <li>Activity transition animations</li>
+</ul>
+
+<p>The Android L Developer Preview lets you easily customize the look of the material theme
+according to your brand identity with a color palette you control. You can tint the app bar and
+the status bar using theme attributes, as shown in Figure 1.</p>
+
+<div style="float:right;margin-left:25px;margin-top:-25px">
+<img src="{@docRoot}preview/material/images/ThemeColors.png" style="width:250px"/>
+<p class="img-caption"><strong>Figure 1.</strong> Customizing the material theme.</p>
+</div>
+
+<p>The system widgets have a new design and touch feedback animations. Activity transitions help
+users navigate your app by providing visual continuity. You can customize the color palette,
+the touch feedback animations, and the activity transitions for your app.</p>
+
+<p>The material theme is defined as:</p>
+
+<ul>
+  <li><code>@android:style/Theme.Material</code> (dark version)</li>
+  <li><code>@android:style/Theme.Material.Light</code> (light version)</li>
+  <li><code>@android:style/Theme.Material.Light.DarkActionBar</code></li>
+</ul>
+
+<p>For a list of material styles that you can use, see the API reference for
+<code>android.R.styles</code>.</p>
+
+<p class="note">
+<strong>Note:</strong> The material theme is only available in the Android L Developer Preview.
+For more information, see <a href="{@docRoot}preview/material/compatibility.html">Compatibility</a>.
+</p>
+
+
+<h2 id="colorpalette">Customize the Color Palette</h2>
+
+<p>To customize the theme's base colors to fit your brand, define your custom colors using
+theme attributes when you inherit from the material theme:</p>
+
+<pre>
+&lt;resources>
+  &lt;!-- inherit from the material theme -->
+  &lt;style name="AppTheme" parent="android:Theme.Material">
+    &lt;!-- Main theme colors -->
+    &lt;!--   your app's branding color (for the app bar) -->
+    &lt;item name="android:colorPrimary">@color/primary&lt;/item>
+    &lt;!--   darker variant of colorPrimary (for contextual app bars) -->
+    &lt;item name="android:colorPrimaryDark">@color/primary_dark&lt;/item>
+
+    &lt;!-- other theme colors -->
+    &lt;item name="android:colorButtonNormal">@color/button_normal&lt;/item>
+    &lt;item name="android:windowBackground">@color/wbackground&lt;/item>
+  &lt;/style>
+&lt;/resources>
+</pre>
+
+
+<h2 id="statusbar">Customize the Status Bar</h2>
+
+<p>The material theme lets you easily customize the status bar, so you can specify a
+color which fits your brand and provides enough contrast to show the white status icons. To
+set a custom color for the status bar, use the <code>android:statusBarColor</code> attribute when
+you extend the material theme.</p>
+
+<p>To handle the color of the status bar yourself (for example, by adding a gradient in the
+background), set the <code>android:statusBarColor</code> attribute to
+<code>&#64;android:color/transparent</code>. You can also use the
+<code>Window.setStatusBarColor</code> method for animations or fading.</p>
+
+<p class="note"><strong>Note:</strong>
+The status bar should almost always have a clear delineation from the primary toolbar, except for
+full-bleed imagery cases and when you use a gradient as a protection.
+</p>
+
+
+<h2 id="inheritance">Theme Inheritance</h3>
+
+<p>In the Android L Developer Preview, elements in XML layout definitions can specify the
+<code>android:theme</code> attribute, which references a theme resource. This attribute modifies
+the theme for the element and any elements inflated below it, which is useful to alter theme
+color palettes in a specific portion of an interface.</p>
\ No newline at end of file
diff --git a/docs/html/preview/material/ui-widgets.jd b/docs/html/preview/material/ui-widgets.jd
new file mode 100644
index 0000000..f18bff9
--- /dev/null
+++ b/docs/html/preview/material/ui-widgets.jd
@@ -0,0 +1,197 @@
+page.title=UI Widgets
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#recyclerview">RecyclerView</a></li>
+  <li><a href="#cardview">CardView</a></li>
+</ol>
+</div>
+</div>
+
+<p>The support library in the Android L Developer Preview contains two new widgets,
+<code>RecyclerView</code> and <code>CardView</code>. Use these widgets to show complex lists
+and cards in your app. These widgets have material design styles and animations by default.</p>
+
+
+<h2 id="recyclerview">RecyclerView</h2>
+
+<p><code>RecyclerView</code> is a more advanced version of <code>ListView</code>. This widget is
+a container for large sets of views that can be recycled and scrolled very efficiently. Use the
+<code>RecyclerView</code> widget when you have lists with elements that change dynamically.</p>
+
+<p><code>RecyclerView</code> is easy to use, because it provides:</p>
+
+<ul>
+  <li>A set of layout managers for positioning items</li>
+  <li>Default animations for common item operations</li>
+</ul>
+
+<p>You also have the flexibility to define custom layout managers and animations for this
+widget.</p>
+
+<p>To use the <code>RecyclerView</code> widget, you have to specify an adapter and a layout
+manager. An <strong>adapter</strong> provides a binding from a dataset to views that are displayed
+within a <code>RecyclerView</code>. For example, if your dataset is an array of strings displayed
+as <code>TextView</code> items, the layout manager asks the adapter to:
+</p>
+
+<ul>
+  <li>Set the text of an existing <code>TextView</code> to one of the strings in the dataset</li>
+  <li>Create new <code>TextView</code> objects</li>
+  <li>Determine the size of the dataset</li>
+</ul>
+
+<p>To create an adapter, you extend the <code>RecyclerView.Adapter</code> class. The details of
+the implementation depend on the specifics of your dataset and the type of views. Fore more
+information, see the examples below.</p>
+
+<img src="/preview/material/images/RecyclerView.png" alt="" id="figure1" style="width:550px"/>
+<p class="img-caption">
+  <strong>Figure 1</strong> - The <code>RecyclerView</code> widget.
+</p>
+
+<p>A <strong>layout manager</strong> positions item views inside a <code>RecyclerView</code> and
+determines when to reuse item views that are no longer visible to the user. To reuse (or
+<em>recycle</em>) a view, a layout manager may ask the adapter to replace the content of the
+view with a different element from the dataset. Recycling views in this manner improves
+performance by avoiding the creation of unnecessary views or performing expensive
+<code>findViewById</code> lookups.
+</p>
+
+<p><code>RecyclerView</code> provides two layout managers you can use:</p>
+
+<ul>
+  <li><code>LinearLayoutManager</code> shows the items in a vertically scrolling list.</li>
+  <li><code>GridLayoutManager</code> shows the items in a rectangular grid.</li>
+</ul>
+
+<p>To create a custom layout, you extend the <code>RecyclerView.LayoutManager</code> class.</p>
+
+<h3>Examples</h3>
+
+<p>To include a <code>RecyclerView</code> in your layout:</p>
+
+<pre>
+&lt;!-- A RecyclerView with some commonly used attributes -->
+&lt;android.support.v7.widget.RecyclerView
+    android:id="@+id/my_recycler_view"
+    android:scrollbars="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
+</pre>
+
+<p>To get the <code>RecyclerView</code> object in your activity:</p>
+
+<pre>
+public class MyActivity extends ActionBarActivity {
+    private RecyclerView mRecyclerView;
+    private RecyclerView.Adapter mAdapter;
+    private RecyclerView.LayoutManager mLayoutManager;
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.my_activity);
+        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
+
+        // improve performance if the size is fixed
+        mRecyclerView.setHasFixedSize(true);
+
+        // use a linear layout manager
+        mLayoutManager = new LinearLayoutManager(this);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+
+        // specify an adapter (see also next example)
+        mAdapter = new MyAdapter(myDataset);
+        mRecyclerView.setAdapter(mAdapter);
+    }
+    ...
+}
+</pre>
+
+<p>To create a simple adapter:</p>
+
+<pre>
+public class MyAdapter extends RecyclerView.Adapter&lt;MyAdapter.ViewHolder> {
+    private String[] mDataset;
+
+    // Provide a reference to the type of views that you are using
+    // (custom viewholder)
+    public static class ViewHolder extends RecyclerView.ViewHolder {
+        public TextView mTextView;
+        public ViewHolder(TextView v) {
+            super(v);
+            mTextView = v;
+        }
+    }
+
+    // Provide a suitable constructor (depends on the kind of dataset)
+    public MyAdapter(String[] myDataset) {
+        mDataset = myDataset;
+    }
+
+    // Create new views (invoked by the layout manager)
+    &#64;Override
+    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+                                                   int viewType) {
+        // create a new view
+        View v = new TextView(parent.getContext());
+        // set the view's size, margins, paddings and layout parameters
+        ...
+        ViewHolder vh = new ViewHolder(v);
+        return vh;
+    }
+
+    // Replace the contents of a view (invoked by the layout manager)
+    &#64;Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        // - get element from your dataset at this position
+        // - replace the contents of the view with that element
+        holder.mTextView.setText(mDataset[position]);
+
+    }
+
+    // Return the size of your dataset (invoked by the layout manager)
+    &#64;Override
+    public int getItemCount() {
+        return mDataset.length;
+    }
+}
+</pre>
+
+
+<h2 id="cardview">CardView</h2>
+
+<p><code>CardView</code> extends the <code>FrameLayout</code> class and lets you show information
+inside a card with optional rounded corners:</p>
+
+<ul>
+  <li>To set the corner radius in your layouts, use the <code>android:cardCornerRadius</code>
+  attribute.</li>
+  <li>To set the corner radius in your code, use the <code>CardView.setRadius</code> method.</li>
+</ul>
+
+<p>To set the background color of a card, use the <code>android:cardBackgroundColor</code>
+attribute.</p>
+
+<p>To include a <code>CardView</code> in your layout:</p>
+
+<pre>
+&lt;!-- A CardView that contains a TextView -->
+&lt;android.support.v7.widget.CardView
+    android:id="@+id/card_view"
+    android:layout_gravity="center"
+    android:layout_width="200dp"
+    android:layout_height="200dp"
+    card_view:cardCornerRadius="4dp">
+
+    &lt;TextView
+        android:id="@+id/info_text"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+&lt;/android.support.v7.widget.CardView>
+</pre>
\ No newline at end of file
diff --git a/docs/html/preview/material/videos/ContactsAnim.mp4 b/docs/html/preview/material/videos/ContactsAnim.mp4
new file mode 100644
index 0000000..073f9dc
--- /dev/null
+++ b/docs/html/preview/material/videos/ContactsAnim.mp4
Binary files differ
diff --git a/docs/html/preview/material/videos/ContactsAnim.ogv b/docs/html/preview/material/videos/ContactsAnim.ogv
new file mode 100644
index 0000000..c5e751b
--- /dev/null
+++ b/docs/html/preview/material/videos/ContactsAnim.ogv
Binary files differ
diff --git a/docs/html/preview/material/videos/ContactsAnim.webm b/docs/html/preview/material/videos/ContactsAnim.webm
new file mode 100644
index 0000000..2a15ff5
--- /dev/null
+++ b/docs/html/preview/material/videos/ContactsAnim.webm
Binary files differ
diff --git a/docs/html/preview/material/views-shadows.jd b/docs/html/preview/material/views-shadows.jd
new file mode 100644
index 0000000..c5884d6
--- /dev/null
+++ b/docs/html/preview/material/views-shadows.jd
@@ -0,0 +1,86 @@
+page.title=Views and Shadows
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#elevation">View Elevation</a></li>
+  <li><a href="#shadows">Shadows and Outlines</a></li>
+  <li><a href="#clip">Clipping Views</a></li>
+</ol>
+</div>
+</div>
+
+<p>In apps with material design, depth has meaning. You should assign higher elevation values to more
+important UI elements in your app. The elevation value of a view determines the size of its
+shadow: views with higher Z values cast bigger shadows. Views only cast shadows on the Z=0 plane
+under an orthographic projection (the views do not scale for different values of Z).</p>
+
+
+<h2 id="elevation">View Elevation</h2>
+
+<p>The Z value for a view has two components, elevation and translation. The elevation is the
+static component, and the translation is used for animations:</p>
+
+<p><code>Z = elevation + translationZ</code></p>
+
+<p>To set the elevation of a view:</p>
+
+<ul>
+  <li>In a layout definition, use the <code>android:elevation</code> attribute.</li>
+  <li>In the code of an activity, use the <code>View.setElevation</code> method.</li>
+</ul>
+
+<p>To set the translation of a view, use the <code>View.setTranslationZ</code> method.</p>
+
+<p>The Z values are measured in the same units as the X and Y values (like <code>dp</code> or
+<code>px</code>).</p>
+
+
+<h2 id="shadows">Shadows and Outlines</h2>
+
+<p>The bounds of a view's background drawable determine the default shape of its shadow. To define
+a custom shape for a shadow, such as an oval, use the <code>View.setOutline</code> method:</p>
+
+<pre>
+View v = findViewById(R.id.my_view);
+
+// add 10px to the static elevation
+v.setTranslationZ(10);
+
+// set an oval shadow
+Outline outline = new Outline();
+outline.setOval(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+myView.setOutline(outline);
+</pre>
+
+<p>An <code>Outline</code> represents the outer shape of a graphics object. You can create
+<code>Outline</code> objects as in this example, or you can obtain the outline from a
+<code>Drawable</code> object with the <code>getOutline</code> method.</p>
+
+<p>The outline of a view also defines the ripple area for touch feedback.</p>
+
+<p>To prevent a view from casting a shadow, set its outline to <code>null</code>.</p>
+
+
+<h2 id="clip">Clipping Views</h2>
+
+<p>The Android L Developer Preview lets you clip a view to its outline area using the
+<code>View.setClipToOutline</code> method. Only rectangle, circle, and round rectangle outlines
+support clipping, as determined by the <code>Outline.canClip</code> method.</p>
+
+<p>To determine if a view has been clipped, use the <code>View.getClipToOutline</code> method.</p>
+
+<pre>
+// clip a view to an oval
+View v = findViewById(R.id.my_view);
+outline.setOval(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+myView.setOutline(outline);
+
+// if the view is not already clipped
+if (v.getClipToOutline() == false) {
+    v.setClipToOutline(true);
+}
+</pre>
\ No newline at end of file
diff --git a/docs/html/preview/preview_toc.cs b/docs/html/preview/preview_toc.cs
new file mode 100644
index 0000000..5920ecc
--- /dev/null
+++ b/docs/html/preview/preview_toc.cs
@@ -0,0 +1,87 @@
+<ul id="nav">
+
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-sdk.html">Set up the Preview SDK
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-devices.html">Set Up Hardware and AVDs
+      </a></div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/api-overview.html">API Overview
+      </a></div>
+  </li>
+  <li class="nav-section">
+
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>preview/material/index.html">Material Design
+      </a></div>
+    <ul>
+      <li><a href="<?cs var:toroot ?>preview/material/get-started.html">Get Started</a></li>
+      <li><a href="<?cs var:toroot ?>preview/material/theme.html">Material Theme</a></li>
+      <li><a href="<?cs var:toroot ?>preview/material/ui-widgets.html">UI Widgets</a></li>
+      <li><a href="<?cs var:toroot ?>preview/material/views-shadows.html">Views and Shadows</a></li>
+      <li><a href="<?cs var:toroot ?>preview/material/animations.html">Animations</a></li>
+      <li><a href="<?cs var:toroot ?>preview/material/compatibility.html">Compatibility</a></li>
+    </ul>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>preview/tv/index.html">TV</a>
+      </div>
+    <ul>
+      <li><a href="<?cs var:toroot ?>preview/tv/start/index.html">
+        Get Started</a></li>
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>preview/tv/ui/index.html">
+          User Interface</a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>preview/tv/ui/layouts.html">
+            Layouts</a></li>
+          <li><a href="<?cs var:toroot ?>preview/tv/ui/navigation.html">
+            Navigation</a></li>
+          <li><a href="<?cs var:toroot ?>preview/tv/ui/browse.html">
+            BrowseFragment</a></li>
+          <li><a href="<?cs var:toroot ?>preview/tv/ui/details.html">
+            DetailsFragment</a></li>
+          <li><a href="<?cs var:toroot ?>preview/tv/ui/in-app-search.html">
+            In-App Search</a></li>
+          <li><a href="<?cs var:toroot ?>preview/tv/ui/recommendations.html">
+            Recommendations</a></li>
+        </ul>
+      </li>
+      <li><a href="<?cs var:toroot ?>preview/tv/games/index.html">
+        Games on TV</a></li>
+      <li><a href="<?cs var:toroot ?>preview/tv/start/hardware-features.html">
+        Hardware Features</a></li>
+      <li><a href="<?cs var:toroot ?>preview/tv/adt-1/index.html">
+        ADT-1</a></li>
+    </ul>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty">
+      <a href="<?cs var:toroot ?>preview/samples.html">Samples</a>
+      </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty">
+
+      <a href="<?cs var:toroot ?>preview/l-developer-preview-reference.zip">Reference</a>
+
+    </div>
+  </li>
+    <li class="nav-section">
+    <div class="nav-section-header empty">
+      <a href="<?cs var:toroot ?>preview/support.html">Support</a>
+      </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section-header empty">
+      <a href="<?cs var:toroot ?>preview/tos.html">Terms of Service</a>
+      </div>
+  </li>
+</ul>
diff --git a/docs/html/preview/samples.jd b/docs/html/preview/samples.jd
new file mode 100644
index 0000000..67404b6
--- /dev/null
+++ b/docs/html/preview/samples.jd
@@ -0,0 +1,16 @@
+page.title=Samples
+
+@jd:body
+
+<p>The code samples for the L Developer Preview are available in the Android SDK Manager under the
+L Preview section. Here is a summary of everything that is available:</p>
+
+<ul>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+ </ul>
diff --git a/docs/html/preview/setup-devices.jd b/docs/html/preview/setup-devices.jd
new file mode 100644
index 0000000..86e4845
--- /dev/null
+++ b/docs/html/preview/setup-devices.jd
@@ -0,0 +1,90 @@
+page.title=Setting Up Hardware and AVDs
+@jd:body
+
+<p>The Android L developer preview provides you with 32-bit system images
+to flash the following devices:
+</p>
+
+<ul>
+  <li>Nexus 5</li>
+  <li>Nexus 7 Wi-Fi (version 2, released in 2013)</li>
+</ul>
+
+<p>In addition, you also get the emulator system images, which includes
+experimental 64-bit system images along with standard 32-bit system images.
+</p>
+
+<h2>Installing the L Preview System Image</h2>
+
+<!-- Will we get an official warning text from the lawyercats? Is this it? -->
+<p class="warning"><b>Warning</b>: This is a preview version of the Android
+system image, and is subject to change. Your use of this system image is
+governed by the Android SDK Preview License Agreement. The Android preview
+system image is not a stable release, and may contain errors and defects that
+can result in damage to your computer systems, devices, and data. The preview
+Android system image is not subject to the same testing as the factory OS and
+can cause your phone and installed services and applications to stop working.
+</p>
+
+
+<ol>
+  <li>Download and extract the Android Developer Preview package to a directory
+  (which we'll call <code>&lt;l_download_dir&gt;</code> in these
+  instructions).</li>
+  <li>Connect your powered-off Android device to your development machine. Put
+  the device in fastboot mode by pressing and holding the following buttons:
+    <ul>
+    <li><strong>Nexus 5:</strong> <i>volume down</i> + <i>volume up</i> +
+        <i>power</i></li>
+    <li><strong>Nexus 7:</strong> <i>volume down</i> + <i>power</i> </li>
+    </ul>
+    <p class="note">Alternatively, you can enter fastboot mode by booting up
+    the device and running <code>adb reboot bootloader</code> with USB debugging
+    turned on.</p>
+  </li>
+  <li>Follow the instructions at
+  <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+  to set up your system for flashing devices.</li>
+  <li>Run the <code>&lt;l_download_dir&gt;/flash-all</code> script
+  corresponding to your platform. This script flashes all of the system data
+  onto the phone.</li> <!-- Confirm names of flash scripts -->
+  <li>(Optional) After flashing is complete, lock your device's bootloader by
+  putting it in   fastboot mode and running <code>fastboot oem lock</code>.
+  (This does not wipe   your device.) Once you do this,  you will not be able to
+  flash your device until you run   run <code>fastboot oem   unlock</code>,
+  which unlocks the bootloader and wipes your device. We recommend you leave the
+  bootloader unlocked until you are done with flashing the device.</li>
+</ol>
+
+<h3>Reverting a Device to Factory Specifications</h3>
+
+  <p>If you want to uninstall the L Preview and revert the device to factory
+specifications, go to <a href="http://developers.google.com/android
+/nexus/images">developers.google.com/android</a> and download the image you want
+to flash to for your device. Follow the instructions on that page to flash the
+image to your device.</p>
+
+
+<h2>Setting up an AVD</h2>
+
+<p>You can set up <a href="{@docRoot}tools/devices/">Android Virtual Devices
+(AVD)</a> and use the emulator to build and test apps with the L Preview.</p>
+
+<p>To create an AVD with the AVD Manager:</p>
+
+<ol>
+  <li>Install the L Preview SDK in your development environment, as described
+      in <a href="{@docRoot}preview/setup-sdk.html">Setting Up the Preview
+      SDK.</a></li>
+  <li>Follow the steps in
+      <a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs with AVD
+      Manager</a>. Use the following settings:
+    <ul>
+      <li><b>Device:</b> Either Nexus 5 or Nexus 7</li>
+      <li><b>Target:</b> <!-- Confirm exact text when we have final distro -->
+       Android L (Preview) - API Level L</li>
+    </ul>
+    <!-- Confirm this works when you can download image through SDK manager! -->
+  </li>
+</ol>
+
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
new file mode 100644
index 0000000..32a33b6
--- /dev/null
+++ b/docs/html/preview/setup-sdk.jd
@@ -0,0 +1,36 @@
+page.title=Setting Up the Preview SDK
+@jd:body
+
+<p>The Preview SDK is available from the Android SDK Manager. <!-- Not yet! -->
+This document assumes that you are familiar with Android app development, such
+as using the Android SDK Manager and creating projects. If you're new to
+Android, see <a href="/training/basics/firstapp/index.html">Building Your First
+App</a> training lesson first.</a></p>
+
+<h2>Download the SDK</h2>
+
+<ol>
+  <li>Start the Android SDK Manager.</li>
+  <li>In the <b>Tools</b> section, select the latest Android <b>SDK Tools</b>,
+    <b>Platform-tools</b>, and <b>Build-tools</b>.</li>
+    <!-- Android L not yet showing up in Android SDK Manager...  -->
+  <li>Select everything under the <b>Android L Developer Preview</b> section and
+    click <b>Install packages...</b></li>
+  <li>Accept the Licensing Agreement for all of the packages and click
+    <b>Install</b>.</li>
+</ol>
+
+<h2>Set up your environment</h2>
+
+<ol>
+  <li>Create a new Android project with the following properties:
+    <ul>
+      <li>Minimum SDK Version: L</li>
+      <li>Target SDK Version: L</li>
+      <li>Build Target: L</li>
+    </ul>
+  </li>
+  <li>Choose the theme <code>Theme.Material</code>
+    <!-- put in name as it appears in Eclipse menu? -->
+
+</ol>
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
new file mode 100644
index 0000000..23ce6ff
--- /dev/null
+++ b/docs/html/preview/support.jd
@@ -0,0 +1,22 @@
+page.title=Support
+
+@jd:body
+
+<p>If you've encountered bugs or have feedback about the L Developer Preview, create
+an issue on our bug tracker</p>
+
+<p>Go to the Bug Tracker</p>
+
+<h2>Release Notes</h2>
+
+<p>June 25, 2014 - Initial Release of the L Developer Preview</p>
+
+<ul>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+  <li></li>
+ </ul>
diff --git a/docs/html/preview/tos.jd b/docs/html/preview/tos.jd
new file mode 100644
index 0000000..602439f
--- /dev/null
+++ b/docs/html/preview/tos.jd
@@ -0,0 +1,9 @@
+page.title=License Agreement
+
+@jd:body
+
+<p><!-- Will this link change before we publish (to a clean version of the doc)?
+  Or will we scrub the doc's comments & revision history? -->
+<a href="https://docs.google.com/a/google.com/document/d/1OixnM1Q890ExOzDB3Z-FDD6Sb2kF4uZQiMxsYVII8F0/edit?usp=sharing">L
+Preview Terms of Service</a>
+</p>
\ No newline at end of file
diff --git a/docs/html/sdk/exploring.jd b/docs/html/sdk/exploring.jd
index 7749060..b34c1cf 100644
--- a/docs/html/sdk/exploring.jd
+++ b/docs/html/sdk/exploring.jd
@@ -5,163 +5,6 @@
 @jd:body
 
 
-<p>The Android SDK is composed of modular packages that you can download separately using
-the Android SDK Manager. For example, when the SDK Tools are updated or a new version of
-the Android platform is released, you can use the SDK Manager to quickly download them to
-your environment. Simply follow the procedures described in <a
-href="{@docRoot}sdk/installing/adding-packages.html">Adding Platforms and Packages</a>.</p>
-
-<p>There are several different packages available for the Android SDK. The table below describes
-most of the available packages and where they're located once you download them.</p>
-
-
-<h2 id="Packages">Available Packages</h2>
-
-
-<table>
-  <tr><th>Package</th><th>Description</th><th>File Location</th></tr>
-  <tr>
-    <td><a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools</a></td>
-    <td>Contains tools for debugging and testing, plus other
-utilities that are required to develop an app. If you've just installed the SDK starter package,
-then you already have the latest version of this package. Make sure you keep this up to date.</td>
-    <td>{@code &lt;sdk>/tools/}</td></tr>
-  <tr><td>SDK Platform-tools</td>
-    <td>Contains platform-dependent tools for developing and debugging
-your application. These tools support the latest features of the Android platform and are typically
-updated only when a new platform becomes available. These tools are always backward compatible with
-older platforms, but you must be sure that you have the latest version of these tools when you
-install a new SDK platform.</td>
-    <td>{@code &lt;sdk>/platform-tools/}</td>
-  </tr>
-  
-  <tr>
-    <td>Documentation</td>
-    <td>An offline copy of the latest documentation for the Android
-platform APIs.</td>
-    <td>{@code &lt;sdk>/docs/}</td>
-  </tr>
-  <tr><td>SDK Platform</td>
-    <td>There's one SDK Platform available for each version of Android. It includes an {@code
-android.jar} file with a fully compliant Android library. In order to build an Android app, you must
-specify an SDK platform as your build target.</td>
-    <td>{@code &lt;sdk>/platforms/&lt;android-version>/}</td>
-  </tr>
-  <tr>
-    <td>System Images</td>
-    <td>Each platform version offers one or more different system images (such as for ARM
-and x86). The Android emulator requires a system image to operate. You should always test your
-app on the latest version of Android and using the emulator with the latest system image is a
-good way to do so.</td>
-    <td>{@code &lt;sdk>/platforms/&lt;android-version>/}</td>
-  </tr>
-  <tr>
-    <td>Sources for Android SDK</td>
-    <td>A copy of the Android platform source code that's useful for
-stepping through the code while debugging your app.</td>
-    <td>{@code &lt;sdk>/sources/}</td>
-  </tr>
-  <tr>
-    <td><a href="{@docRoot}tools/samples/index.html">Samples for SDK</a></td>
-    <td>A collection of sample apps that demonstrate a variety of the
-platform APIs. These are a great resource to browse Android app code. The API Demos app in
-particular provides a huge number of small demos you should explore.</td>
-    <td>{@code &lt;sdk>/platforms/&lt;android-version>/samples/}</td>
-  </tr>
-  <tr>
-    <td><a href="http://developers.google.com/android">Google APIs</a></td>
-    <td>An SDK add-on that provides both a platform you can use to develop an app
-using special Google APIs and a system image for the emulator so you can test your app using the
-Google APIs.</td>
-    <td>{@code &lt;sdk>/add-ons/}</td>
-  </tr>
-  
-  <tr>
-    <td><a href="{@docRoot}tools/support-library/index.html">Android Support</a></td>
-    <td>A static library you can include in your app sources in order to use powerful
-APIs that aren't available in the standard platform. For example, the support library
-contains versions of the {@link android.support.v4.app.Fragment} class that's compatible with
-Android 1.6 and higher (the class was originally introduced in Android 3.0) and the {@link
-android.support.v4.view.ViewPager} APIs that allow you to easily build a side-swipeable UI.</td>
-    <td>{@code &lt;sdk>/extras/android/support/}</td>
-  </tr>
-  <tr>
-    <td><a href="{@docRoot}google/play/billing/index.html">Google Play Billing</a></td>
-    <td>Provides the static libraries and samples that allow you to
-integrate billing services in your app with Google Play.</td>
-    <td>{@code &lt;sdk>/extras/google/}</td>
-  </tr>
-  <tr>
-    <td><a href="{@docRoot}google/play/licensing/index.html">Google Play Licensing</a></td>
-    <td>Provides the static libraries and samples that allow you to perform license verification for
-your app when distributing with Google Play.</td>
-    <td>{@code &lt;sdk>/extras/google/}</td>
-  </tr>
-</table>
-
-<p>The above table is not comprehensive and you can <a
-href="#AddingSites">add new sites</a> to download additional packages from third-parties.</p>
-
-<p>In some cases, an SDK package may require a specific minimum revision of
-another package or SDK tool. For example, there may be a dependency between the ADT Plugin for
-Eclipse and
-the SDK Tools package. When you install the SDK Tools
-package, you should also upgrade to the required version of ADT (if you
-are developing in Eclipse). In this case,  the major version number for your ADT plugin should
-always match the revision number of your SDK Tools (for example, ADT 8.x requires SDK Tools r8).
-</p>
-
-<p>The development tools will notify you with debug warnings if there is dependency that you need to
-address. The Android SDK Manager also enforces dependencies by requiring that you download any
-packages that are needed by those you have selected.</p>
-
-
-
-
-
-<h2 id="AddingSites">Adding New Sites</h2>
-
-<p>By default, <strong>Available Packages</strong> displays packages available from the
-<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host
-their own Android SDK add-ons, then download the SDK add-ons
-from those sites.</p>
-
-<p>For example, a mobile carrier or device manufacturer might offer additional
-API libraries that are supported by their own Android-powered devices. In order
-to develop using their libraries, you must install their Android SDK add-on, if it's not already
-available under <em>Third party Add-ons</em>. </p>
-
-<p>If a carrier or device manufacturer has hosted an SDK add-on repository file
-on their web site, follow these steps to add their site to the Android SDK
-Manager:</p>
-
-<ol>
-  <li>Select <strong>Available Packages</strong> in the left panel.</li>
-  <li>Click <strong>Add Add-on Site</strong> and enter the URL of the
-<code>repository.xml</code> file. Click <strong>OK</strong>.</li>
-</ol>
-<p>Any SDK packages available from the site will now be listed under a new item named
-<strong>User Add-ons</strong>.</p>
-
-
-
-
-<h2 id="troubleshooting">Troubleshooting</h2>
-
-<p><strong>Problems connecting to the SDK repository</strong></p>
-
-<p>If you are using the Android SDK Manager to download packages and are encountering
-connection problems, try connecting over http, rather than https. To switch the
-protocol used by the Android SDK Manager, follow these steps: </p>
-
-<ol>
-  <li>With the Android SDK Manager window open, select "Settings" in the
-  left pane. </li>
-  <li>On the right, in the "Misc" section, check the checkbox labeled "Force
-  https://... sources to be fetched using http://..." </li>
-  <li>Click <strong>Save &amp; Apply</strong>.</li>
-</ol>
-
 
 
 
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index e7f78e8..dc3b9dd 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -206,12 +206,10 @@
 
 
 <div id="next-steps" style="display:none;position:absolute;width:inherit">
-  <p>Now that you've downloaded the Android SDK, you don't need to return here
-  for SDK updates. The SDK tools allow you to
-  install additional packages and future updates from the SDK Manager.</p>
-  <p>For instructions about setting up your Android SDK for the first time,
-  read <a id="next-link" href="{@docRoot}sdk/installing/bundle.html">Setting
-  Up the ADT Bundle</a>.</p>
+  <p>You're just a few steps away from building apps for Android!</p>
+  <p>In a moment, you'll be redirected to <a
+  id="next-link" href="{@docRoot}sdk/installing/index.html">Installing the
+  Android SDK</a>.</p>
 
 </div><!-- end next-steps -->
 
@@ -232,7 +230,6 @@
 </div>
 
 
-
 </div><!-- end TOS -->
 
 
@@ -255,16 +252,30 @@
 <b>ADT (Android Developer Tools)</b> to
 streamline your Android app development.</p>
 
-<p>With a single download, the ADT Bundle
+
+<!-- this appears when viewing the online docs -->
+<div class="online" style="margin-bottom:85px">
+
+<a class="big button subtitle" id="download-bundle-button"
+href="" style="width:295px;display:block;margin:25px 0" ></a>
+
+<p id="not-supported">Choose the SDK package for your OS from the table below.</p>
+
+
+  <p>With a single download, the Eclipse ADT bundle
 includes everything you need to begin developing apps:</p>
 <ul>
 <li>Eclipse + ADT plugin</li>
 <li>Android SDK Tools</li>
 <li>Android Platform-tools</li>
-<li>The latest Android platform</li>
-<li>The latest Android system image for the emulator</li>
+<li>A version of the Android platform</li>
+<li>A version of the Android system image for the emulator</li>
 </ul>
 
+</div>
+<!-- end online -->
+
+
 
 <!-- this appears when viewing the offline docs -->
 <p class="offline">
@@ -277,52 +288,44 @@
 
 
 <div class="col-7" style="margin-right:0;">
-  <img src="{@docRoot}images/sdk-cube.png" alt="" height=264 />
+  <img src="{@docRoot}images/tools-home.png" alt="" height="347" width="400" />
 
-<!-- this appears when viewing the online docs -->
-<div class="online">
-
-<a class="big button subtitle" id="download-bundle-button"
-href="" style="display:none;width:265px;margin:0 auto;display:block" ></a>
-
-
-
-
-<p id="not-supported">Choose the SDK package for your OS from the table below.</p>
-
-</div>
-<!-- end online -->
 
 </div><!-- end col-7 -->
 
 
 
 
+<div class="col-7" style="background: #ddd;
+    padding: 30px 20px; width:350px; margin:20px 0 0 20px;">
+
+  <h3 style="margin-top:0">
+  <a href="/sdk/installing/studio.html">Get Android Studio Beta</a>
+  </h3>
+
+  <p>
+  Android Studio is a new IDE powered by IntelliJ that provides new features and improvements
+  over ADT. It's currently in beta but will be the official Android IDE once it's ready.</p>
+  <p style="margin: 0;">
+  <a href="/sdk/installing/studio.html">Learn more about Android Studio</a></p>
+  </div>
+
+
 
 
 <!-- alternative SDK options -->
-<div class="col-13" style="margin:0;">
+<div class="col-13" style="margin:-70px 0 0;">
 
 
-<!-- this appears only when viewing the online docs -->
-<div class="online caution">
-<h3 style="margin:0 0 10px 0;font-size:14px">Android Studio Early Access Preview</h3>
+<p style="width:340px">If you prefer to use an existing version of Eclipse or another IDE,
+you can instead download the stand-alone Android SDK Tools:</p>
 
-<p>A new Android development environment called Android Studio,
-based on IntelliJ IDEA, is now available as an <strong>early access preview</strong>.
-For more information, see
-<a href="{@docRoot}sdk/installing/studio.html">Getting Started with Android Studio</a>.</p>
 
-</div>
-
-<p>If you prefer to use an existing version of Eclipse or another IDE,
-you can instead take a more customized approach to installing
-the Android SDK. See the following instructions:</p>
 
 
 <h4 id="ExistingIDE"><a href='' class="expandable"
   onclick="toggleExpandable(this,'.myide');hideExpandable('.pax,.reqs');return false;"
-  >USE AN EXISTING IDE</a></h4>
+  >GET THE SDK FOR AN EXISTING IDE</a></h4>
 
 <div class="col-13 myide" style="margin:0 0 15px;display:none;">
 
@@ -335,13 +338,11 @@
 <a class="button subtitle" id="download-tools-button" href="" style="display:none" ></a>
   </p>
 
-
 </div>
 
 
 
 
-
 <h4 id="Requirements"><a href='' class="expandable"
   onclick="toggleExpandable(this,'.reqs');hideExpandable('.pax,.myide');return false;"
   >SYSTEM REQUIREMENTS</a></h4>
@@ -361,23 +362,9 @@
 </ul>
 </div>
 
-<div class="col-6 reqs" style="margin:0 0 15px 20px;display:none;">
-<h5>Eclipse IDE</h5>
-    <ul>
-      <li><a href="http://eclipse.org/mobile/">Eclipse</a> 3.7.2 (Indigo) or greater
-<p class="note"><strong>Note:</strong> Eclipse 3.6 (Helios) is no longer
-supported with the latest version of ADT.</p></li>
-      <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
-in most Eclipse IDE packages) </li>
-      <li><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 6</a>
-        (JRE alone is not sufficient)</li>
-      <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">Android Development Tools plugin</a>
-(recommended)</li>
-      <li><strong>Not</strong> compatible with GNU Compiler for Java (gcj)</li>
-    </ul>
+<div class="col-7 reqs" style="margin:0 0 80px 20px;display:none;">
 
-
-<h5>Other development environments</h5>
+<h5>Development tools</h5>
     <ul>
       <li><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 6</a>
         (JRE alone is not sufficient)</li>
@@ -387,6 +374,4 @@
 
 <p class="note"><strong>Note:</strong> Some Linux distributions may include JDK 1.4 or Gnu Compiler
 for Java, both of which are <em>not</em> supported for Android development. </p>
-</div><!-- end col-7 reqs -->
-
-
+</div><!-- end reqs -->
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index bba936e..e6c0118 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -1,63 +1,226 @@
-page.title=Adding Platforms and Packages
+page.title=Adding SDK Packages
 
 @jd:body
 
+<style>
+ol.large {
+  margin-left:0;
+}
+ol.large > li {
+  list-style-position: inside;
+  list-style-type:none;
+  margin:30px 0 0 0;
+  padding:30px 20px;
+  background:#eee;
+}
+ol.large > li:nth-child(odd) {
+}
+ol.large > li:before {
+  display:inline;
+  left:-40px;
+  float:left;
+  width:20px;
+  font-size:20px;
+  line-height:20px;
+}
+ol.large > li > h2 {
+  font-size:20px;
+  line-height:20px;
+  padding:0 0 0 20px;
+  margin:0 0 20px 0;
+  display:inline-block;
+  font-weight:normal;
+}
+ol.large > li:nth-child(1):before {
+  content:"1. ";
+}
+ol.large > li:nth-child(2):before {
+  content:"2. ";
+}
+ol.large > li:nth-child(3):before {
+  content:"3. ";
+}
+ol.large > li:nth-child(4):before {
+  content:"4. ";
+}
+ol.large > li:nth-child(5):before {
+  content:"5. ";
+}
+ol.large > li:nth-child(6):before {
+  content:"6. ";
+}
+</style>
 
-<p>The Android SDK separates tools, platforms, and other components into packages you can
-  download using the Android SDK Manager. The original
-SDK package you've downloaded includes only the SDK Tools. To develop an Android app,
-you also need to download at least one Android platform and the latest SDK Platform-tools.</p>
 
-<ol>
-<li>Launch the SDK Manager.
-<p>If you've used the Windows installer to install the SDK tools, you should already have the
-Android SDK Manager open. Otherwise, you can launch the Android SDK Manager in one of the following
-ways:</p>
+<p>
+By default, the Android SDK does not include everything you need to start developing.
+The SDK separates tools, platforms, and other components into packages you can
+download as needed using the
+<a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.
+So before you can start, there are a few packages you should add to your Android SDK.</p>
+
+<p>To start adding packages, launch the Android SDK Manager in one of the following ways:</p>
 <ul>
-  <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
-SDK directory.</li>
-  <li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the
-Android SDK, then execute <code>android sdk</code>.</li>
+  <li>In Eclipse or Android Studio, click <strong>SDK Manager</strong>
+<img src="{@docRoot}images/tools/sdk-manager-studio.png"
+style="vertical-align:bottom;margin:0;height:17px" /> in the toolbar.</li>
+  <li>If you're not using Eclipse or Android Studio:
+    <ul>
+      <li>Windows: Double-click the <code>SDK Manager.exe</code> file at the root of the Android
+  SDK directory.</li>
+      <li>Mac/Linux: Open a terminal and navigate to the <code>tools/</code> directory in the
+  Android SDK, then execute <code>android sdk</code>.</li>
+    </ul>
+  </li>
 </ul>
+
+<p>When you open the SDK Manager for the first time, several packages will be selected by
+default. Leave these selected, but be sure you have everything you need
+to get started by following these steps:</p>
+
+
+<ol class="large">
+<li>
+  <h2 id="GetTools" class="norule">Get the latest SDK tools</h2>
+
+<img src="/images/sdk_manager_packages.png" alt="" width="350" style="float:right;margin-left:20px" />
+
+  <p>As a minimum when setting up the Android SDK,
+  you should download the latest tools and Android platform:</p>
+  <ol>
+   <li>Open the Tools directory and select:
+     <ul>
+       <li><strong>Android SDK Tools</strong></li>
+       <li><strong>Android SDK Platform-tools</strong></li>
+       <li><strong>Android SDK Build-tools</strong> (highest version)</li>
+     </ul>
+   </li>
+   <li>Open the first Android X.X folder (the latest version) and select:
+     <ul>
+      <li><strong>SDK Platform</strong></li>
+      <li>A system image for the emulator, such as <br>
+      <strong>ARM EABI v7a System Image</strong></li>
+     </ul>
+   </li>
+  </ol>
 </li>
 
-<li>The SDK Manager shows all the SDK packages available for you to add to your Android SDK.
-As a minimum configuration for your SDK, we recommend you install the following:
-<ul>
- <li>The latest Tools packages (check the <strong>Tools</strong> folder).</li>
- <li>The latest version of Android (check the first <strong>Android</strong> folder).</li>
- <li>The Android Support Library (open the <strong>Extras</strong> folder and check
-  <strong>Android Support Library</strong>).</li>
-</ul>
+<li>
+  <h2 id="GetSupportLib" class="norule">Get the support library for additional APIs</h2>
 
-<p>Once you've chosen your packages, click <strong>Install</strong>. The Android SDK Manager
-installs the selected packages into your Android SDK environment.</li>
+  <div class="sidebox">
+    <p>The support library is required for:</p>
+    <ul>
+      <li><a href="{@docRoot}wear/index.html">Android Wear</a></li>
+      <li><a href="{@docRoot}tv/index.html">Android TV</a></li>
+      <li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
+    </ul>
+
+    <p>It also provides these popular APIs:</p>
+    <ul>
+      <li><a href="{@docRoot}reference/android/support/v4/widget/DrawerLayout.html">Navigation
+      drawer</a></li>
+      <li><a href="{@docRoot}reference/android/support/v4/view/ViewPager.html">Swipe views</a></li>
+      <li><a href="{@docRoot}reference/android/support/v7/app/ActionBar.html">Backward-compatible
+      action bar</a></li>
+    </ul>
+  </div>
+
+  <p>The <a href="{@docRoot}tools/support-library/features.html">Android Support Library</a>
+  provides an extended set of APIs that are compatible with most versions of Android.</p>
+
+  <p>Open the <strong>Extras</strong> directory and select:</p>
+     <ul>
+       <li><strong>Android Support Repository</strong></li>
+       <li><strong>Android Support Library</strong></li>
+     </ul>
+
+  <p>&nbsp;</p>
+  <p>&nbsp;</p>
+
+</li>
+
+
+<li>
+  <h2 id="GetGoogle" class="norule">Get Google Play services for even more APIs</h2>
+
+  <div class="sidebox">
+
+    <p>The Google Play services APIs provide a variety of features and services for your Android
+    apps, such as:</p>
+    <ul>
+      <li><a href="{@docRoot}google/play-services/plus.html">User authentication</a></li>
+      <li><a href="{@docRoot}google/play-services/maps.html">Google Maps</a></li>
+      <li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
+      <li><a href="{@docRoot}google/play-services/games.html">Games achievements and
+      leaderboards</a></li>
+      <li><a href="{@docRoot}google/play-services/index.html">And much more</a></li>
+    </ul>
+  </div>
+
+  <p>To develop with Google APIs, you need the Google Play services package:</p>
+  <p>Open the <strong>Extras</strong> directory and select:</p>
+     <ul>
+       <li><strong>Google Repository</strong></li>
+       <li><strong>Google Play services</strong></li>
+     </ul>
+
+  <p class="note"><strong>Note:</strong> Google Play services APIs are not available on all
+  Android-powered devices, but are available on all devices with Google Play Store. To use these
+  APIs in the Android emulator, you must also install the the <strong>Google APIs</strong>
+  system image from the latest Android X.X directory in the SDK Manager.</p>
+</li>
+
+
+<li>
+  <h2 id="Install" class="norule">Install the packages</h2>
+  <p>Once you've selected all the desired packages, continue to install:</p>
+  <ol>
+   <li>Click <strong>Install X packages</strong>.</li>
+   <li>In the next window, double-click each package name on the left
+   to accept the license agreement for each.</li>
+   <li>Click <strong>Install</strong>.</li>
+  </ol>
+  <p>The download progress is shown at the bottom of the SDK Manager window.
+  <strong>Do not exit the SDK Manager</strong> or it will cancel the download.</p>
+</li>
+
+<li>
+  <h2 id="Build" class="norule">Build something!</h2>
+
+<p>With the above packages now in your Android SDK, you're ready to build apps
+for Android. As new tools and other APIs become available, simply launch the SDK Manager
+  to download the new packages for your SDK.</p>
+
+<p>Here are a few options for how you should proceed:</p>
+
+<div class="cols" style="padding:10px 0">
+<div class="col-4">
+<h3>Get started</h3>
+<p>If you're new to Android development, learn the basics of Android apps by following
+the guide to <strong><a href="{@docRoot}training/basics/firstapp/index.html"
+>Building Your First App</a></strong>.</p>
+
+</div>
+<div class="col-4 box">
+<h3>Build for wearables</h3>
+<p>If you're ready to start building apps for Android wearables, see the guide to
+<strong><a href="{@docRoot}wear/preview/start.html">Building Apps for Android Wear</a></strong>.</p>
+
+</div>
+<div class="col-4 box">
+<h3>Use Google APIs</h3>
+<p>To start using Google APIs, such as Maps or
+Play Game services, see the guide to
+<strong><a href="{@docRoot}google/play-services/setup.html">Setting Up Google Play
+Services</a></strong>.</p>
+
+</div>
+</div><!-- end cols -->
+
+
+</li>
+
 </ol>
 
-<p>With these packages installed, you're ready to start developing.
-To get started, read <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</p>
-
-<img src="/images/sdk_manager_packages.png" alt="" height="396" />
-<p class="img-caption"><strong>Figure 1.</strong> The Android SDK Manager shows the
-SDK packages that are available, already installed, or for which an update is available.</p>
-
-
-
-<h3>Additional information</h3>
-
-<ul>
-  <li>For more information about using the SDK Manager and some of the available packages,
-see the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> document.</li>
-  <li>This web site provides all information you need to develop Android apps, including <a
-href="{@docRoot}design/index.html">design guidelines</a>,
-<a href="{@docRoot}training/index.html">developer training</a>, <a
-href="{@docRoot}reference/packages.html">API reference</a>, and information
-about how you can <a href="{@docRoot}distribute/index.html">distribute your app</a>. We recommend
-you begin by reading <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</li>
-  <li>For additional resources about developing and distributing your app, see the
-<a href="{@docRoot}support.html">Developer Support Resources</a>.</li>
-</ul>
-
 
diff --git a/docs/html/sdk/installing/bundle.jd b/docs/html/sdk/installing/bundle.jd
index 1f7da55..22bdd11 100644
--- a/docs/html/sdk/installing/bundle.jd
+++ b/docs/html/sdk/installing/bundle.jd
@@ -1,45 +1,3 @@
 page.title=Setting Up the ADT Bundle
 
 @jd:body
-
-
-<p>The ADT Bundle provides everything you need to start developing apps, including
-a version of the Eclipse IDE with built-in <b>ADT (Android Developer Tools)</b> to
-streamline your Android app development.
-If you haven't already, go download the <a href="{@docRoot}sdk/index.html"
->Android ADT Bundle</a>. (If you downloaded the SDK Tools only, for use with an
-existing IDE, you should instead read
-<a href="{@docRoot}sdk/installing/index.html">Setting Up an Existing IDE</a>.)</p>
-
-<h3>Install the SDK and Eclipse IDE</h3>
-<ol>
-<li>Unpack the ZIP file
-(named {@code adt-bundle-&lt;os_platform>.zip}) and save it to an appropriate location,
-such as a "Development" directory in your home directory.</li>
-<li>Open the {@code adt-bundle-&lt;os_platform>/eclipse/} directory and launch
-<strong>eclipse</strong>.</li>
-</ol>
-
-<p>That's it! The IDE is already loaded with the Android Developer Tools plugin and
-the SDK is ready to go. To start developing, read <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</p>
-
-<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
-from the {@code adt-bundle-&lt;os_platform>} directory. If you move the {@code eclipse}
-or {@code sdk} directory, ADT will not be able to locate the SDK and you'll
-need to manually update the ADT preferences.</p>
-
-<h3>Additional information</h3>
-
-<p>As you continue developing apps, you may need to install additional versions
-of Android for the emulator and other packages such as the library for
-Google Play In-app Billing. To install more packages, use
-the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p>
-
-<p>Everything you need to develop Android apps is on this web site, including <a
-href="{@docRoot}design/index.html">design guidelines</a>,
-<a href="{@docRoot}training/index.html">developer training</a>, <a
-href="{@docRoot}reference/packages.html">API reference</a>, and information
-about how you can <a href="{@docRoot}distribute/index.html">distribute your app</a>.
-For additional resources about developing and distributing your app, see the
-<a href="{@docRoot}support.html">Developer Support Resources</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 6b63ba7..3671726 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -1,19 +1,213 @@
-page.title=Setting Up an Existing IDE
+page.title=Installing the Android SDK
 
 @jd:body
 
-
-<p>You should have already downloaded the <a href="{@docRoot}sdk/index.html#ExistingIDE"
->Android SDK Tools</a>. (If you downloaded the ADT Bundle, you should instead read
-<a href="{@docRoot}sdk/installing/bundle.html">Setting Up the ADT Bundle</a>.)</p>
-
-<p>The SDK Tools package is not the complete SDK environment. It includes only the core SDK tools, which you can
-use to download the rest of the SDK packages (such as the latest system image).</p>
+<style>
+.paging-links {
+  margin:0 0 80px;
+}
+.paging-links .next-page-link {
+  right:initial;
+}
+.procedure-box {
+  padding:20px 20px 5px;
+  margin-bottom:1em;
+  background:#eee;
+}
+</style>
 
 
-<div id="win" class="docs" style="display:none">
 
-<h3>Getting started on Windows</h3>
+<!-- ###################    ADT BUNDLE     ####################### -->
+<div id="adt" heading="Installing the Eclipse ADT Bundle" style="display:none">
+
+
+<p>The Eclipse ADT Bundle provides everything you need to start developing apps, including
+the Android SDK tools and a version of the Eclipse IDE with built-in ADT
+(Android Developer Tools) to streamline your Android app development.</p>
+
+<p>If you didn't download the Eclipse ADT bundle, go <a href="{@docRoot}sdk/index.html"
+><b>download the Eclipse ADT bundle now</b></a>, or switch to the
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
+install</a> instructions</i>.</p>
+
+<div class="procedure-box">
+<p><b>To set up the ADT Bundle:</b></p>
+<ol>
+<li>Unpack the ZIP file
+(named {@code adt-bundle-&lt;os_platform>.zip}) and save it to an appropriate location,
+such as a "Development" directory in your home directory.</li>
+<li>Open the {@code adt-bundle-&lt;os_platform>/eclipse/} directory and launch
+<strong>Eclipse</strong>.</li>
+</ol>
+
+<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
+from the {@code adt-bundle-&lt;os_platform>} directory. If you move the {@code eclipse/}
+or {@code sdk/} directory, ADT will not be able to locate the SDK and you'll
+need to manually update the ADT preferences.</p>
+</div>
+
+<p>Eclipse with ADT is now ready and loaded with the Android developer tools, but there are still
+a couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################    END ADT BUNDLE    ##################### -->
+
+
+
+
+
+
+<!-- ################    STUDIO    ##################### -->
+<div id="studio" heading="Installing Android Studio" style="display:none">
+
+<p>Android Studio provides everything you need to start developing apps, including
+the Android SDK tools and the Android Studio IDE (powered by IntelliJ) to
+streamline your Android app development.</p>
+
+<p>If you didn't download Android Studio, go <a href="{@docRoot}sdk/installing/studio.html"
+><b>download Android Studio now</b></a>, or switch to the
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt">Eclipse ADT
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
+install</a> instructions.</p>
+
+
+<p>Before you set up Android Studio, be sure you have installed
+JDK 6 or greater (the JRE alone is not sufficient). To check if you
+have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
+If the JDK is not available or the version is lower than 6,
+<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" class="external-link"
+>go download JDK</a>.</p>
+
+
+<div class="procedure-box">
+
+<p id="instructions-toggle"
+style="float:right;font-size:13px"><a href='' onclick='showAll();return false;'
+>[ Show instructions for all platforms ]</a></p>
+
+<div class="win docs" style="display:none">
+
+<p><b>To set up Android Studio on Windows:</b></p>
+  <ol>
+    <li>Launch the downloaded EXE file, {@code android-studio-bundle-&lt;version&gt;.exe}.</li>
+    <li>Follow the setup wizard to install Android Studio.
+
+    <p>On some Windows systems, the launcher script does not find where Java is installed.
+      If you encounter this problem,
+      you need to set an environment variable indicating the correct location.</p>
+      <p>Select <strong>Start menu > Computer > System Properties >
+      Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment
+      Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to
+      your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
+    </p>
+    </li>
+    
+  </ol>
+
+
+<p>The individual tools and
+other SDK packages are saved within the Android Studio application directory.
+If you need to access the tools directly, use a terminal to navigate into the application and locate
+the {@code sdk/} directory. For example:</p>
+<p><code>\Users\&lt;user&gt;\AppData\Local\Android\android-studio\sdk\</code></p>
+
+
+
+</div><!-- end windows -->
+
+
+<div class="mac docs" style="display:none">
+
+<p><b>To set up Android Studio on Mac OSX:</b></p>
+  <ol>
+    <li>Open the downloaded DMG file, {@code android-studio-bundle-&lt;version&gt;.dmg}.</li>
+    <li>Drag and drop Android Studio into the Applications folder.
+      <p>
+      Depending on your security settings, when you attempt to open Android Studio, you might
+      see a warning that says the package is damaged and should be moved to the trash. If this
+      happens, go to <strong>System Preferences > Security &amp; Privacy</strong> and under
+      <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
+      Then open Android Studio again.</p>
+    </li>
+  </ol>
+
+<p>The individual tools and
+other SDK packages are saved within the Android Studio application directory.
+If you need access the tools directly, use a terminal to navigate into the application and locate
+the {@code sdk/} directory. For example:</p>
+<p><code>/Applications/Android\ Studio.app/sdk/</code></p>
+
+
+</div><!-- end mac -->
+
+
+<div class="linux docs" style="display:none">
+
+<p><b>To set up Android Studio on Linux:</b></p>
+
+  <ol>
+    <li>Unpack the downloaded Tar file, {@code android-studio-bundle-&lt;version&gt;.tgz}, into an appropriate
+    location for your applications.
+    <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
+    in a terminal and execute {@code studio.sh}.
+      <p>You may want to add {@code android-studio/bin/} to your PATH environmental
+      variable so that you can start Android Studio from any directory.</p>
+    </li>
+  </ol>
+
+</div><!-- end linux -->
+</div><!-- end procedure box -->
+
+<p>Android Studio is now ready and loaded with the Android developer tools, but there are still a
+couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################    END STUDIO    ##################### -->
+
+
+
+
+
+
+
+
+
+<!-- ################    JUST SDK TOOLS    ##################### -->
+<div id="tools" heading="Installing the Stand-alone SDK Tools" style="display:none">
+
+
+<p>The stand-alone SDK Tools package does not include a complete Android development environment.
+It includes only the core SDK tools, which you can access from a command line or with a plugin
+for your favorite IDE (if available).</p>
+
+<p>If you didn't download the SDK tools, go <a href="{@docRoot}sdk/index.html"
+><b>download the SDK now</b></a>,
+or switch to the <a href="{@docRoot}sdk/installing/index.html?pkg=adt">Eclipse ADT
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
+install</a> instructions.</p>
+
+
+<div class="procedure-box">
+<p id="instructions-toggle"
+style="float:right;font-size:13px"><a href='' onclick='showAll();return false;'
+>[ Show instructions for all platforms ]</a></p>
+
+<div class="win docs" style="display:none">
+
+<p><b>To get started on Windows:</b></p>
+
 <p>Your download package is an executable file that starts an installer. The installer checks your machine
   for required tools, such as the proper Java SE Development Kit (JDK) and installs it if necessary.
   The installer then saves the Android SDK Tools into a default location (or you can specify the location).</p>
@@ -21,15 +215,9 @@
 <ol>
 <li>Double-click the executable ({@code .exe} file) to start the install.</li>
 <li>Make a note of the name and location in which it saves the SDK on your system&mdash;you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
 the SDK tools from the command line.</li>
-<li>Once the installation completes, the installer offers to start the Android SDK Manager.
-If you'll be using Eclipse, <strong>do not</strong> start the Android SDK Manager,
-and instead move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>.
-<p>If you're using a different IDE,
-start the SDK Manager and read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</p>
+<li>Once the installation completes, the installer starts the Android SDK Manager.
 </li>
 </ol>
 
@@ -37,51 +225,37 @@
 
 
 
-<div id="mac" class="docs" style="display:none">
+<div class="mac docs" style="display:none">
 
-<h3>Getting started on Mac</h3>
+<p><b>To get started on Mac OSX:</b></p>
 
-<ol>
-<li>Unpack the ZIP file you've downloaded. By default, it's unpacked
+<p>Unpack the ZIP file you've downloaded. By default, it's unpacked
 into a directory named <code>android-sdk-mac_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.
+such as a "Development" directory in your home directory.</p>
 
 <p>Make a note of the name and location of the SDK directory on your system&mdash;you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
 the SDK tools from the command line.</p>
-</li>
-<li>If you're using Eclipse, move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>. Otherwise, if you're using a different IDE,
-read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</li>
-</ol>
 
 </div>
 
 
 
 
-<div id="linux" class="docs" style="display:none">
+<div class="linux docs" style="display:none">
 
-<h3>Getting started on Linux</h3>
+<p><b>To get started on Linux:</b></p>
 
-<ol>
-<li>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
+<p>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
 into a directory named <code>android-sdk-linux_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.
+such as a "Development" directory in your home directory.</p>
 
 <p>Make a note of the name and location of the SDK directory on your system&mdash;you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
 the SDK tools from the command line.</p>
-</li>
-<li>If you're using Eclipse, move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>. Otherwise, if you're using a different IDE,
-read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</li>
-</ol>
 
 
-<h5 id="Troubleshooting"><a href='' class="expandable"
+<h5 id="Troubleshooting" style="margin-bottom:15px"><a href='' class="expandable"
   onclick="toggleExpandable(this,'#ubuntu-trouble');return false;"
   >Troubleshooting Ubuntu</a></h5>
 
@@ -122,38 +296,129 @@
 </div><!-- end ubuntu trouble -->
 
 
+</div><!-- end linux -->
+</div><!-- end procedure box -->
+
+
+<p>The Android SDK tools are now ready to begin developing apps, but there are still a
+couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################    END JUST TOOLS    ##################### -->
+
+
+
+
+
+<!-- ################    DEFAULT    ##################### -->
+<style>
+h3.large-link {
+  display:inline-block;
+  width:100%;
+  text-align:center;
+  border:1px solid #258aaf;
+  padding:10px 0;
+  color:inherit;
+}
+</style>
+
+<div id="default" style="display:none">
+
+<p>If you haven't already done so, <b><a href="{@docRoot}sdk/index.html">click here to download
+the Android SDK</a></b>. </p>
+
+<p>Otherwise, select which SDK package you want to install:</p>
+
+<div class="cols" style="margin-bottom:60px">
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt">
+<h3 class="large-link">Eclipse ADT</h3>
+</a>
 </div>
 
-<p style="margin-top:2em;"><a href='' onclick='showAll();return false;'>Information for other platforms</a></p>
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio">
+<h3 class="large-link">Android Studio</h3></a>
+</div>
+
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=tools">
+<h3 class="large-link">Stand-alone SDK Tools</h3></a>
+</div>
+</div>
+
+
+</div>
+<!-- ################    END DEFAULT    ##################### -->
+
+
+
+
+
 
 <script>
-  var $osDocs;
-  if (navigator.appVersion.indexOf("Win")!=-1) {
-    $osDocs = $('#win');
-  } else if (navigator.appVersion.indexOf("Mac")!=-1) {
-    $osDocs = $('#mac');
-  } else if (navigator.appVersion.indexOf("Linux")!=-1) {
-    $osDocs = $('#linux');
-  }
 
-  if ($osDocs.length) {
-    // reveal only the docs for this OS
-    $osDocs.show();
-  } else {
-    // not running a compatible OS, so just show all the docs
-    $('.docs').show();
-  }
+// Show proper instructions based on downloaded SDK package
+var package = getUrlParam("pkg");
+if (package == "tools") {
+  // Show the SDK Tools (other IDE) instructions
+  $("h1").text($("#tools").attr('heading'));
+  $("#tools").show();
+} else if (package == "adt") {
+  // Show the ADT instructions
+  $("h1").text($("#adt").attr('heading'));
+  $("#adt").show();
+} else if (package == "studio") {
+  // Show the Android Studio instructions
+  $("h1").text($("#studio").attr('heading'));
+  $("#studio").show();
+} else {
+  // Show the default page content so user can select their setup
+  $("#default").show();
+}
 
-  function showAll() {
-    $('.docs').each(function() {
-      if (!$(this).is(':visible')) {
-        console.log('show')
-        $(this).show();
-      } else {
-        console.log('hide')
-        $(this).hide();
-        $osDocs.show();
-      }
-    });
+// Show the proper instructions based on machine OS
+var $osDocs;
+if (navigator.appVersion.indexOf("Win")!=-1) {
+  $osDocs = $('.win');
+} else if (navigator.appVersion.indexOf("Mac")!=-1) {
+  $osDocs = $('.mac');
+} else if (navigator.appVersion.indexOf("Linux")!=-1) {
+  $osDocs = $('.linux');
+}
+
+if ($osDocs.length) {
+  // reveal only the docs for this OS
+  $osDocs.show();
+} else {
+  // not running a compatible OS, so just show all the docs
+  $('.docs').show();
+}
+
+
+/* Shows all the machine OS instructions */
+function showAll() {
+  $('.docs').show();
+  $("#instructions-toggle").hide();
+}
+
+/* Returns the value for the given URL parameter */
+function getUrlParam(param) {
+  var url = window.location.search.substring(1);
+  var variables = url.split('&');
+  for (var i = 0; i < variables.length; i++) {
+    var paramName = variables[i].split('=');
+    if (escape(paramName[0]) == param) {
+      return escape(paramName[1]);
+    }
   }
+}
+
+
+
 </script>
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 7bf366c..1e87cd8 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -15,19 +15,28 @@
 UI, debug your app, and export signed (or unsigned) app packages (APKs) for distribution.
 </p>
 
-<p>If you need to install Eclipse, you can download it from <a href=
-"http://www.eclipse.org/downloads/">eclipse.org/downloads/</a>.</p>
+<p class="note"><strong>Note:</strong> You should install the ADT plugin
+only if you already have an Eclipse installation that you want to continue using. If you do not
+have Eclipse installed, you should instead <b><a href="{@docRoot}sdk/index.html">install
+the complete Android SDK</a></b>, which includes the latest IDE for Android developers.</p>
 
-
-<p class="note"><strong>Note:</strong> If you prefer to work in a different IDE, you do not need to
-install Eclipse or ADT. Instead, you can directly use the SDK tools to build and
-debug your application.</p>
-
+<p>Your existing Eclipse installation must meet these requirements:</p>
+    <ul>
+      <li><a href="http://eclipse.org/mobile/">Eclipse</a> 3.7.2 (Indigo) or greater
+<p class="note"><strong>Note:</strong> Eclipse 3.6 (Helios) is no longer
+supported with the latest version of ADT.</p></li>
+      <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
+in most Eclipse IDE packages) </li>
+      <li><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 6</a>
+        (JRE alone is not sufficient)</li>oid Development Tools plugin</a>
+(recommended)</li>
+      <li><strong>Not</strong> compatible with GNU Compiler for Java (gcj)</li>
+    </ul>
 
 
 <h2 id="Download">Download the ADT Plugin</h2>
 
-
+<p>To add the ADT plugin to Eclipse:</p>
 <ol>
     <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Install New
 Software</strong>.</li>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 1b47f7f..8ac6163 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -1,5 +1,5 @@
-page.title=Getting Started with Android Studio
-page.tags=studio
+page.title=Android Studio
+page.tags="studio"
 @jd:body
 
 
@@ -7,7 +7,7 @@
 
 <div style="position:relative;min-height:660px;">
 
-<h3 style="color:#f80">EARLY ACCESS PREVIEW</h3>
+<h3 style="color:#FF4444;margin:-30px 0 20px">BETA</h3>
 
 <div id="tos" style="position:absolute;display:none;width:inherit;">
 <div class="col-13" style="margin:0;">&nbsp;</div><!-- provides top margin for content -->
@@ -183,23 +183,21 @@
 
 
 
-
-
 <div id="main">
 
-<div class="figure" style="width:400px;margin-top:-20px">
+<div class="figure" style="width:400px;margin-top:-75px">
 <img src="{@docRoot}images/tools/android-studio.png" height="330" width="400" style="margin-bottom:20px" />
 
 <a class="big button subtitle" id="download-ide-button"
-href="" style="display:none;width:265px;margin:0 auto;display:block;font-size:18px" ></a>
-<div style="width:290px;padding:10px 40px 0 60px;font-size:12px;line-height:16px">
+href="" style="display:none;width:368px;margin:0 auto;display:block;font-size:18px" ></a>
+<div style="margin:20px 0 0 0">
 
 <p style="margin-bottom:8px">This download includes:</p>
-<ul>
-<li>Android Studio <b>early access preview</b></li>
-<li>All the Android SDK Tools to design, test, debug, and profile your app</li>
-<li>The latest Android platform to compile your app</li>
-<li>The latest Android system image to run your app in the emulator</li>
+<ul style="margin-bottom:20px">
+<li>Android Studio Beta</li>
+<li>All the Android SDK Tools to design, test, and debug your app</li>
+<li>A version of the Android platform to compile your app</li>
+<li>A version of the Android system image to run your app in the emulator</li>
 </ul>
 
 </div>
@@ -208,36 +206,34 @@
 
 
 <p>Android Studio is a new Android development environment based on IntelliJ
-IDEA. Similar to Eclipse with the
-ADT Plugin, Android Studio provides integrated Android developer tools
-for development and debugging. On top of the
+IDEA. It provides new features and improvements over Eclipse ADT
+and will be the official Android IDE once it's ready. On top of the
 capabilities you expect from IntelliJ, Android Studio offers:</p>
 
 <ul>
-  <li>Gradle-based build support.</li>
-  <li>Android-specific refactoring and quick fixes.</li>
-  <li>Lint tools to catch performance, usability, version compatibility and other problems.</li>
-  <li>ProGuard and app-signing capabilities. </li>
-  <li>Template-based wizards to create common Android designs and components.</li>
-  <li>A rich layout editor that allows you to drag-and-drop UI components, preview layouts on
-  multiple screen configurations, and much more.</li>
+  <li>Flexible Gradle-based build system.</li>
+  <li>Build variants and multiple APK generation.</li>
+  <li>Expanded template support for Google Services and various device types.</li>
+  <li>Rich layout editor with support for theme editing.</li>
+  <li>Lint tools to catch performance, usability, version compatibility, and other problems.</li>
+  <li>ProGuard and app-signing capabilities.</li>
   <li>Built-in support for <a
   href="http://android-developers.blogspot.com/2013/06/adding-backend-to-your-app-in-android.html"
   class="external-link">Google Cloud Platform</a>, making it easy to integrate Google Cloud
-  Messaging and App Engine as server-side components.
+  Messaging and App Engine.
 </ul>
 
-<p class="caution"><strong>Caution:</strong> Android Studio is currently available as
-an <strong>early access preview</strong>. Several features
-are either incomplete or not yet implemented and you may encounter bugs. If you are not
+<p class="caution"><strong>Caution:</strong> Android Studio is currently in
+<strong>beta</strong>. Some features
+are not yet implemented and you may encounter bugs. If you are not
 comfortable using an unfinished product, you may want to instead
-download (or continue to use) the
-<a href="{@docRoot}sdk/index.html">ADT Bundle</a> (Eclipse with the ADT Plugin).</p>
+download (or continue to use)
+<a href="{@docRoot}sdk/index.html">Eclipse with ADT</a>.</p>
 
 
-<h4 style="clear:right;text-align:right;margin-right:50px"><a href='' class="expandable"
+<h4 style="margin-top: 20px;"><a href='' class="expandable"
   onclick="toggleExpandable(this,'.pax');return false;"
-  >DOWNLOAD FOR OTHER PLATFORMS</a></h4>
+  >VIEW ALL DOWNLOADS AND SIZES</a></h4>
 
 <div class="pax col-13 online" style="display:none;margin:0;">
 
@@ -290,6 +286,73 @@
 
 
 
+<h2 style="margin-bottom: 0px;">Android Studio vs. Eclipse ADT Comparison</h2>
+
+<p>
+The following table lists some key differences between Android Studio Beta and
+<a href="{@docRoot}sdk/index.html">Eclipse with ADT</a>.
+</p>
+
+<style>
+td.yes {
+  color: #669900;
+}
+td.no {
+  color: #CC0000;
+}
+</style>
+
+<table>
+  <tbody><tr>
+    <th>Feature</th>
+    <th>Android Studio</th>
+    <th>ADT</th>
+  </tr>
+  <tr>
+    <td>Build system</td>
+    <td><a href="http://www.gradle.org/" class="external-link">Gradle</a></td>
+    <td><a href="http://ant.apache.org/" class="external-link">Ant</a></td>
+    </tr>
+    <tr>
+
+    <td>Maven-based build dependencies</td>
+    <td class="yes">Yes</td>
+    <td class="no">No</td>
+    </tr>
+
+    <td>Build variants and multiple-APK generation (great for Android Wear)</td>
+    <td class="yes">Yes</td>
+    <td class="no">No</td>
+    </tr>
+
+    <tr>
+    <td>Advanced Android code completion and refactoring</td>
+    <td class="yes">Yes</td>
+    <td class="no">No</td>
+    </tr>
+  <tr>
+    <td>Graphical layout editor</td>
+    <td class="yes">Yes</td>
+    <td class="yes">Yes</td>
+   </tr>
+   <tr>
+  </tr>
+
+    <tr>
+    <td>APK signing and keystore management</td>
+    <td class="yes">Yes</td>
+    <td class="yes">Yes</td>
+    </tr>
+
+    <tr>
+    <td>NDK support</td>
+    <td class="no">Coming soon</td>
+    <td class="yes">Yes</td>
+    </tr>
+ </tbody></table>
+
+
+
 <h2 id="Updating">Updating from older versions</h2>
 
 <p>If you already have Android Studio installed, in most cases, you can upgrade to the latest
@@ -298,7 +361,7 @@
 Check for updates</strong>) to see whether an update is available.</p>
 
 <p>If an update is not available,
-follow the <a href="#Installing">installation instructions</a> below and replace your existing
+click the button above to download and replace your existing
 installation.</p>
 
 <div class="caution">
@@ -311,100 +374,6 @@
 the Android SDK Manager.</p>
 </div>
 
-
-<h2 id="Installing">Installing Android Studio</h2>
-<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
-have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
-If JDK is not available or the version is lower than 6,
-<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">download
-JDK from here</a>.</p>
-<p>To install Android Studio:</p>
-<ol>
-<li>Download the <strong>Android Studio</strong> package from above.</li>
-<li>Install Android Studio and the SDK tools:
-  <p><b>Windows:</b></p>
-  <ol>
-    <li>Launch the downloaded EXE file, {@code android-studio-bundle-&lt;version&gt;.exe}.</li>
-    <li>Follow the setup wizard to install Android Studio.
-
-    <div class="caution"><p><strong>Known issue:</strong>
-      On some Windows systems, the launcher script does not find where Java is installed.
-      If you encounter this problem,
-      you need to set an environment variable indicating the correct location.</p>
-      <p>Select <strong>Start menu > Computer > System Properties >
-      Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment
-      Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to
-      your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
-    </div>
-    </li>
-
-  </ol>
-  <p><b>Mac OS X:</b></p>
-  <ol>
-    <li>Open the downloaded DMG file, {@code android-studio-bundle-&lt;version&gt;.dmg}.</li>
-    <li>Drag and drop Android Studio into the Applications folder.
-
-    <div class="caution"><p><strong>Known issue:</strong>
-      Depending on your security settings, when you attempt to open Android Studio, you might
-      see a warning that says the package is damaged and should be moved to the trash. If this
-      happens, go to <strong>System Preferences > Security &amp; Privacy</strong> and under
-      <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
-      Then open Android Studio again.</p>
-    </div>
-    </li>
-
-  </ol>
-  <p><b>Linux:</b></p>
-  <ol>
-    <li>Unpack the downloaded Tar file, {@code android-studio-bundle-&lt;version&gt;.tgz}, into an appropriate
-    location for your applications.
-    <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
-    in a terminal and execute {@code studio.sh}.
-      <p>You may want to add {@code android-studio/bin/} to your PATH environmental
-      variable so that you can start Android Studio from any directory.</p>
-    </li>
-  </ol>
-</li>
-</ol>
-
-<p>That's it! You're ready to start developing apps with Android Studio.</p>
-
-<div class="note">
-<p><strong>Note:</strong> On Windows and Mac, the individual tools and
-other SDK packages are saved within the Android Studio application directory.
-To access the tools directly, use a terminal to navigate into the application and locate
-the {@code sdk/} directory. For example:</p>
-<p>Windows: <code>\Users\&lt;user&gt;\AppData\Local\Android\android-studio\sdk\</code></p>
-<p>Mac: <code>/Applications/Android\ Studio.app/sdk/</code></p>
-</div>
-
-<p>For a list of some known issues, see <a
-href="http://tools.android.com/knownissues">tools.android.com/knownissues</a>.</p>
-
-
-<h2 id="Start">Starting a Project</h2>
-
-<p>When you launch Android Studio for the first time, you'll see a Welcome
-screen that offers several ways to get started:</p>
-
-<ul>
-  <li>To start building a new app, click <strong>New Project</strong>.
-    <p>This starts the New Project wizard, which helps you set up a project using an app template.
-  </li>
-  <li>To import an existing Android app project, click <strong>Import Project</strong>.
-    <p class="note"><strong>Note:</strong> If you previously developed your Android project
-    with Eclipse, you should first use the new export feature in the ADT plugin to prepare
-    your project with the new Gradle build system. For more information, read
-    <a href="{@docRoot}sdk/installing/migrate.html">Migrating from Eclipse</a> and
-    <a href="{@docRoot}sdk/installing/studio-build.html">Building Your Project with
-    Gradle</a>.</p>
-  </li>
-</ul>
-
-<p>For additional help using Android Studio, read <a
-href="{@docRoot}sdk/installing/studio-tips.html">Tips and Tricks</a>.</p>
-
-
 <p>As you continue developing apps, you may need to install additional versions
 of Android for the emulator and other packages such as the <a
 href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
@@ -601,8 +570,8 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.5.2</span>"
-        + "<br/> <span class='small'>for " + os + "</span>");
+    $('#download-ide-button').append("Download Android Studio Beta <span class='small'>v0.5.2</span>"
+        + "<br/> <span class='small'>with the Android SDK for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
   } else {
@@ -644,9 +613,13 @@
 
   function onDownloadForRealz(link) {
     if ($("input#agree").is(':checked')) {
-      $("#tos").hide();
-      $("#main").show();
-      location.hash = "Updating";
+      $("h1").text('Now redirecting to the install instructions...');
+      $("#tos").slideUp();
+      $("#jd-content .jd-descr").fadeOut('slow', function() {
+        setTimeout(function() {
+          window.location = "/sdk/installing/index.html?pkg=studio";
+        }, 1000);
+      });
       _gaq.push(['_trackEvent', 'SDK', 'Android Studio', $("#downloadForRealz").html()]);
       return true;
     } else {
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index e748b12..89b3857 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -5,6 +5,7 @@
 <div id="qv">
   <h2>In this document</h2>
   <ol>
+    <li><a href="#device-developer-options">Enabling On-device Developer Options</a></li>
     <li><a href="#setting-up">Setting up a Device for Development</a>
       <ol>
         <li><a href="#VendorIds">USB Vendor IDs</a></li>
@@ -43,6 +44,29 @@
 platform, in different screen sizes and orientations, and more.</p>
 
 
+<h2 id="developer-device-options" style="margin-bottom: 0px;">Enabling On-device Developer Options</h2>
+
+<img src="/images/tools/dev-options-inmilk.png" alt="" style="float:right;margin-left:30px">
+
+<p>Android-powered devices have a host of developer options that you can
+access on the phone, which let you:</p>
+<ul>
+  <li>Enable debugging over USB.</li>
+  <li>Quickly capture bug reports onto the device.</li>
+  <li>Show CPU usage on screen.</li>
+  <li>Draw debugging information on screen such as layout bounds,
+    updates on GPU views and hardware layers, and other information.</li>
+  <li>Plus many more options to simulate app stresses or enable debugging options.</li>
+</ul>
+<p>To access these settings, open the <em>Developer options</em> in the
+system Settings. On Android 4.2 and higher, the Developer options screen is
+hidden by default. To make it visible, go to
+<b>Settings &gt; About phone</b> and tap <b>Build number</b> seven times. Return to the previous
+screen to find Developer options at the bottom.</p>
+
+
+
+
 <h2 id="setting-up">Setting up a Device for Development</h2>
 
 <p>With an Android-powered device, you can develop and debug your Android applications just as you
diff --git a/docs/html/tools/help/sdk-manager.jd b/docs/html/tools/help/sdk-manager.jd
index 57271bb..b084237 100644
--- a/docs/html/tools/help/sdk-manager.jd
+++ b/docs/html/tools/help/sdk-manager.jd
@@ -3,7 +3,9 @@
 
 
 <p>The Android SDK separates tools, platforms, and other components into packages you can
-  download using the SDK Manager.</p>
+  download using the SDK Manager. For example, when the SDK Tools are updated or a new version of
+the Android platform is released, you can use the SDK Manager to quickly download them to
+your environment.</p>
 
 <p>You can launch the SDK Manager in one of the following ways:</p>
 <ul>
@@ -25,6 +27,14 @@
 SDK packages that are available, already installed, or for which an update is available.</p>
 
 
+<p>There are several different packages available for the Android SDK. The table below describes
+most of the available packages and where they're located in your SDK directory
+once you download them.</p>
+
+
+
+
+
 <h2 id="Recommended">Recommended Packages</h2>
 
 <p>Here's an outline of the packages required and those we recommend you use:
@@ -69,3 +79,77 @@
 <p class="note"><strong>Tip:</strong> For easy access to the SDK tools from a command line, add the
 location of the SDK's <code>tools/</code> and
 <code>platform-tools</code> to your <code>PATH</code> environment variable.</p>
+
+
+<p>The above list is not comprehensive and you can <a
+href="#AddingSites">add new sites</a> to download additional packages from third-parties.</p>
+
+<p>In some cases, an SDK package may require a specific minimum revision of
+another package or SDK tool.
+The development tools will notify you with warnings if there is dependency that you need to
+address. The Android SDK Manager also enforces dependencies by requiring that you download any
+packages that are needed by those you have selected.</p>
+
+
+
+
+
+<h2 id="AddingSites">Adding New Sites</h2>
+
+<p>By default, <strong>Available Packages</strong> displays packages available from the
+<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host
+their own Android SDK add-ons, then download the SDK add-ons
+from those sites.</p>
+
+<p>For example, a mobile carrier or device manufacturer might offer additional
+API libraries that are supported by their own Android-powered devices. In order
+to develop using their libraries, you must install their Android SDK add-on, if it's not already
+available under <em>Third party Add-ons</em>. </p>
+
+<p>If a carrier or device manufacturer has hosted an SDK add-on repository file
+on their web site, follow these steps to add their site to the Android SDK
+Manager:</p>
+
+<ol>
+  <li>Select <strong>Available Packages</strong> in the left panel.</li>
+  <li>Click <strong>Add Add-on Site</strong> and enter the URL of the
+<code>repository.xml</code> file. Click <strong>OK</strong>.</li>
+</ol>
+<p>Any SDK packages available from the site will now be listed under a new item named
+<strong>User Add-ons</strong>.</p>
+
+
+
+
+<h2 id="troubleshooting">Troubleshooting</h2>
+
+<p><strong>Problems connecting to the SDK repository</strong></p>
+
+<p>If you are using the Android SDK Manager to download packages and are encountering
+connection problems, try connecting over http, rather than https. To switch the
+protocol used by the Android SDK Manager, follow these steps: </p>
+
+<ol>
+  <li>With the Android SDK Manager window open, select "Settings" in the
+  left pane. </li>
+  <li>On the right, in the "Misc" section, check the checkbox labeled "Force
+  https://... sources to be fetched using http://..." </li>
+  <li>Click <strong>Save &amp; Apply</strong>.</li>
+</ol>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index b29b87c..fb4659f 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -1,53 +1,35 @@
 <ul id="nav">
 
   <li class="nav-section">
-    <div class="nav-section-header empty">
-        <a href="<?cs var:toroot ?>tools/index.html"><span class="en">Developer Tools</span></a>
-    </div>
-  </li>
-
-  <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot
 ?>sdk/index.html"><span class="en">Download</span></a></div>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/installing/bundle.html">
-          <span class="en">Setting Up the ADT Bundle</span></a></li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/index.html">
+          <span class="en">Installing the SDK</span></a></li>
 
-      <li class="nav-section">
-        <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>sdk/installing/index.html"><span class="en">Setting Up
-    an Existing IDE</span></a></div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
-              <span class="en">Installing the Eclipse Plugin</span></a></li>
-        <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
-            <span class="en">Adding Platforms and Packages</span></a></li>
-        </ul>
-      </li>
-
-      <li class="nav-section">
-        <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>sdk/installing/studio.html">Android Studio</a>
-        </div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">
-              Migrating from Eclipse</a></li>
-          <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
-              Tips and Tricks</a></li>
-          <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
-              Using the Layout Editor</a></li>
-          <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
-              Building Your Project with Gradle</a></li>
-          <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
-              Debugging with Android Studio</a></li>
-          </ul>
-      </li>
-      <li><a href="<?cs var:toroot ?>sdk/exploring.html">
-          <span class="en">Exploring the SDK</span></a></li>
-      <li><a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">Download the NDK</a>
-      </li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
+          <span class="en">Adding SDK Packages</span></a></li>
     </ul>
   </li>
+  
+
+  <li class="nav-section">
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>sdk/installing/studio.html">Android Studio</a>
+    </div>
+    <ul>
+      <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">
+          Migrating from Eclipse</a></li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
+          Tips and Tricks</a></li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
+          Using the Layout Editor</a></li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
+          Building Your Project with Gradle</a></li>
+      <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+          Debugging with Android Studio</a></li>
+      </ul>
+  </li>
 
   <li class="nav-section">
     <div class="nav-section-header">
@@ -174,7 +156,13 @@
 class="en">Tools Help</span></a></div>
     <ul>
       <li><a href="<?cs var:toroot ?>tools/help/adb.html">adb</a></li>
-      <li><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></li>
+      <li class="nav-section">
+        <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
+              <span class="en">Installing the Eclipse Plugin</span></a></li>
+        </ul>
+      </li>
       <li><a href="<?cs var:toroot ?>tools/help/android.html">android</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/avd-manager.html">AVD Manager</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/bmgr.html">bmgr</a>
@@ -244,6 +232,11 @@
     </ul>
   </li>
 
+  <li class="nav-section">
+    <div class="nav-section-header empty">
+      <a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">NDK</a>
+    </div>
+  </li>
 
   <li class="nav-section">
     <div class="nav-section-header">
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
new file mode 100644
index 0000000..bbbda67
--- /dev/null
+++ b/docs/html/training/articles/keystore.jd
@@ -0,0 +1,107 @@
+page.title=Android Keystore System
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#WhichShouldIUse">Choosing Between a Keychain or the Android Keystore Provider</a></li>
+      <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider
+      </a></li>
+      <ol>
+        <li><a href="#GeneratingANewPrivateKey">Generating a New Private Key</a></li>
+        <li><a href="#WorkingWithKeyStoreEntries">Working with Keystore Entries</a></li>
+        <li><a href="#ListingEntries">Listing Entries</a></li>
+        <li><a href="#SigningAndVerifyingData">Signing and Verifying Data</a></li>
+      </ol>
+    </ol>
+
+    <h2>Blog articles</h2>
+    <ol>
+      <li><a
+        href="http://android-developers.blogspot.com/2012/03/unifying-key-store-access-in-ics.html">
+          <h4>Unifying Key Store Access in ICS</h4>
+      </a></li>
+    </ol>
+  </div>
+</div>
+
+<p>The Android Keystore system lets you store private keys
+  in a container to make it more difficult to extract from the
+  device. Once keys are in the keystore, they can be used for
+  cryptographic operations with the private key material remaining
+  non-exportable.</p>
+
+<p>The Keystore system is used by the {@link
+  android.security.KeyChain} API as well as the Android
+  Keystore provider feature that was introduced in Android 4.3
+  (API level 18). This document goes over when and how to use the
+  Android Keystore provider.</p>
+
+<h2 id="WhichShouldIUse">Choosing Between a Keychain or the
+Android Keystore Provider</h2>
+
+<p>Use the {@link android.security.KeyChain} API when you want
+  system-wide credentials. When an app requests the use of any credential
+  through the {@link android.security.KeyChain} API, users get to
+  choose, through a system-provided UI, which of the installed credentials
+  an app can access. This allows several apps to use the
+  same set of credentials with user consent.</p>
+
+<p>Use the Android Keystore provider to let an individual app store its own
+  credentials that only the app itself can access.
+  This provides a way for apps to manage credentials that are usable
+  only by itself while providing the same security benefits that the
+  {@link android.security.KeyChain} API provides for system-wide
+  credentials. This method requires no user interaction to select the credentials.</p>
+
+<h2 id="UsingAndroidKeyStore">Using Android Keystore Provider</h2>
+
+<p>
+To use this feature, you use the standard {@link java.security.KeyStore}
+and {@link java.security.KeyPairGenerator} classes along with the
+{@code AndroidKeyStore} provider introduced in Android 4.3 (API level 18).</p>
+
+<p>{@code AndroidKeyStore} is registered as a {@link
+  java.security.KeyStore} type for use with the {@link
+  java.security.KeyStore#getInstance(String) KeyStore.getInstance(type)}
+  method and as a provider for use with the {@link
+  java.security.KeyPairGenerator#getInstance(String, String)
+  KeyPairGenerator.getInstance(algorithm, provider)} method.</p>
+
+<h3 id="GeneratingANewPrivateKey">Generating a New Private Key</h3>
+
+<p>Generating a new {@link java.security.PrivateKey} requires that
+  you also specify the initial X.509 attributes that the self-signed
+  certificate will have. You can replace the certificate at a later
+  time with a certificate signed by a Certificate Authority.</p>
+
+<p>To generate the key, use a {@link java.security.KeyPairGenerator}
+  with {@link android.security.KeyPairGeneratorSpec}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java generate}
+
+<h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3>
+
+<p>Using the {@code AndroidKeyStore} provider takes place through
+  all the standard {@link java.security.KeyStore} APIs.</p>
+
+<h4 id="ListingEntries">Listing Entries</h4>
+
+<p>List entries in the keystore by calling the {@link
+  java.security.KeyStore#aliases()} method:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java list}
+
+<h4 id="SigningAndVerifyingData">Signing and Verifying Data</h4>
+
+<p>Sign data by fetching the {@link
+  java.security.KeyStore.Entry} from the keystore and using the
+  {@link java.security.Signature} APIs, such as {@link
+  java.security.Signature#sign()}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java sign}
+
+<p>Similarly, verify data with the {@link java.security.Signature#verify(byte[])} method:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java verify}
diff --git a/docs/html/training/cloudsync/backupapi.jd b/docs/html/training/cloudsync/backupapi.jd
index a5436c6..fd35ada 100644
--- a/docs/html/training/cloudsync/backupapi.jd
+++ b/docs/html/training/cloudsync/backupapi.jd
@@ -41,7 +41,7 @@
 
 <h2 id="register">Register for the Android Backup Service</h2>
 <p>This lesson requires the use of the <a
-  href="http://code.google.com/android/backup/index.html">Android Backup
+  href="{@docRoot}google/backup/index.html">Android Backup
   Service</a>, which requires registration.  Go ahead and <a
   href="http://code.google.com/android/backup/signup.html">register here</a>.  Once
 that's done, the service pre-populates an XML tag for insertion in your Android
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index eb7df3d..cf7117c 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -6,6 +6,16 @@
 
 @jd:body
 
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 2.2 (API level 8) and higher</li>
+</ul>
+</div>
+</div>
+
 <p>By providing powerful APIs for internet connectivity, the Android framework
 helps you build rich cloud-enabled apps that sync their data to a remote web
 service, making sure all your devices always stay in sync, and your valuable
diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd
deleted file mode 100644
index a99e378..0000000
--- a/docs/html/training/tv/index.jd
+++ /dev/null
@@ -1,59 +0,0 @@
-page.title=Designing for TV
-page.tags=input,screens
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
-  <li>Android 2.0 (API Level 5) or higher</li>
-</ul>
-
-</div>
-</div>
-
-<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=zsRnRLh-O34">
-<div>
-    <h3>Video</h3>
-    <p>DevBytes: Design for Large Displays - Part 1</p>
-</div>
-</a>
-
-<p> 
-  Smart TVs powered by Android bring your favorite Android apps to the best screen in your house. 
-  Thousands of apps in the Google Play Store are already optimized for TVs. This class shows how 
-  you can optimize your Android app for TVs, including how to build a layout that 
-  works great when the user is ten feet away and navigating with a remote control. 
-</p> 
-
-<h2>Lessons</h2> 
- 
-<dl> 
-  <dt><b><a href="optimizing-layouts-tv.html">Optimizing Layouts for TV</a></b></dt>
-    <dd>Shows you how to optimize app layouts for TV screens, which have some unique characteristics such as:
-    <ul>
-      <li>permanent "landscape" mode</li>
-      <li>high-resolution displays</li>
-      <li>"10 foot UI" environment.</li>
-    </ul>
-    </dd>
- 
-  <dt><b><a href="optimizing-navigation-tv.html">Optimizing Navigation for TV</a></b></dt>
-    <dd>Shows you how to design navigation for TVs, including: 
-    <ul>
-      <li>handling D-pad navigation</li>
-      <li>providing navigational feedback</li>
-      <li>providing easily-accessible controls on the screen.</li>
-    </ul>
-    </dd>
-
-  <dt><b><a href="unsupported-features-tv.html">Handling features not supported on TV</a></b></dt>
-    <dd>Lists the hardware features that are usually not available on TVs. This lesson also shows you how to 
-    provide alternatives for missing features or check for missing features and disable code at run time.</dd>
-</dl> 
diff --git a/docs/html/training/tv/optimizing-layouts-tv.jd b/docs/html/training/tv/optimizing-layouts-tv.jd
deleted file mode 100644
index a6db052..0000000
--- a/docs/html/training/tv/optimizing-layouts-tv.jd
+++ /dev/null
@@ -1,246 +0,0 @@
-page.title=Optimizing Layouts for TV
-parent.title=Designing for TV
-parent.link=index.html
-
-trainingnavtop=true
-next.title=Optimizing Navigation for TV
-next.link=optimizing-navigation-tv.html
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
-  <li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li>
-  <li><a href="#MakeTextControlsEasyToSee">Make Text and Controls Easy to See</a></li>
-  <li><a href="#DesignForLargeScreens">Design for High-Density Large Screens</a></li>
-  <li><a href="#HandleLargeBitmaps">Design to Handle Large Bitmaps</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
-  <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
-</ul>
-
-</div>
-</div>
-
-<p>
-When your application is running on a television set, you should assume that the user is sitting about 
-ten feet away from the screen. This user environment is referred to as the 
-<a href="http://en.wikipedia.org/wiki/10-foot_user_interface">10-foot UI</a>. To provide your 
-users with a usable and enjoyable experience, you should style and lay out your UI accordingly..
-</p>
-<p>
-This lesson shows you how to optimize layouts for TV by:
-</p>
-<ul>
-  <li>Providing appropriate layout resources for landscape mode.</li>
-  <li>Ensuring that text and controls are large enough to be visible from a distance.</li>
-  <li>Providing high resolution bitmaps and icons for HD TV screens.</li>
-</ul>
-
-<h2 id="DesignLandscapeLayouts">Design Landscape Layouts</h2> 
-
-<p>
-TV screens are always in landscape orientation. Follow these tips to build landscape layouts optimized for TV screens:
-</p> 
-<ul>
-  <li>Put on-screen navigational controls on the left or right side of the screen and save the 
-  vertical space for content.</li>
-  <li>Create UIs that are divided into sections, by using <a href="{@docRoot}guide/components/fragments.html">Fragments</a> 
-  and use view groups like {@link android.widget.GridView} instead 
-  of {@link android.widget.ListView} to make better use of the 
-  horizontal screen space.</li>
-  <li>Use view groups such as {@link android.widget.RelativeLayout} 
-  or {@link android.widget.LinearLayout} to arrange views. 
-  This allows the Android system to adjust the position of the views to the size, alignment, 
-  aspect ratio, and pixel density of the TV screen.</li>
-  <li>Add sufficient margins between layout controls to avoid a cluttered UI.</li>
-</ul> 
- 
-<p>
-For example, the following layout is optimized for TV:
-</p>
-
-<img src="{@docRoot}images/training/panoramio-grid.png" />
-
-<p>
-In this layout, the controls are on the lefthand side. The UI is displayed within a 
-{@link android.widget.GridView}, which is well-suited to landscape orientation.
-In this layout both GridView and Fragment have the width and height set 
-dynamically, so they can adjust to the screen resolution. Controls are added to the left side Fragment programatically at runtime.
-The layout file for this UI is {@code res/layout-land-large/photogrid_tv.xml}.
-(This layout file is placed in {@code layout-land-large} because TVs have large screens with landscape orientation. For details refer to 
-<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.)</p>
-
-res/layout-land-large/photogrid_tv.xml
-<pre>
-&lt;RelativeLayout
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent" &gt;
-
-    &lt;fragment
-        android:id="@+id/leftsidecontrols"
-        android:layout_width="0dip"
-        android:layout_marginLeft="5dip"
-        android:layout_height="match_parent" /&gt;
-
-    &lt;GridView        
-        android:id="@+id/gridview"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" /&gt;
-
-&lt;/RelativeLayout>
-</pre>
-
-<p>
-To set up action bar items on the left side of the screen, you can also include the <a
-href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarLibrary">
-Left navigation bar library</a> in your application to set up action items on the left side 
-of the screen, instead of creating a custom Fragment to add controls:
-</p>
-
-<pre>
-LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this);
-</pre>
-
-<p>
-When you have an activity in which the content scrolls vertically, always use a left navigation bar; 
-otherwise, your users have to scroll to the top of the content to switch between the content view and 
-the ActionBar. Look at the  
-<a href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarDemo">
-Left navigation bar sample app</a> to see how to simple it is to include the left navigation bar in your app.
-</p>
-
-<h2 id="MakeTextControlsEasyToSee">Make Text and Controls Easy to See</h2>
-<p>
-The text and controls in a TV application's UI should be easily visible and navigable from a distance.
-Follow these tips to make them easier to see from a distance :
-</p>
-
-<ul>
-  <li>Break text into small chunks that users can quickly scan.</li>
-  <li>Use light text on a dark background. This style is easier to read on a TV.</li>
-  <li>Avoid lightweight fonts or fonts that have both very narrow and very broad strokes. Use simple sans-serif 
-  fonts and use anti-aliasing to increase readability.</li>
-  <li>Use Android's standard font sizes:
-  <pre>
-  &lt;TextView
-        android:id="@+id/atext"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical"
-        android:singleLine="true"
-        android:textAppearance="?android:attr/textAppearanceMedium"/&gt;
-  </pre></li>
-  <li>Ensure that all your view widgets are large enough to be clearly visible to someone sitting 10 feet away 
-  from the screen (this distance is greater for very large screens).  The best way to do this is to use 
-  layout-relative sizing rather than absolute sizing, and density-independent pixel units instead of absolute 
-  pixel units. For example, to set the width of a widget, use wrap_content instead of a pixel measurement, 
-  and to set the margin for a widget, use dip instead of px values.
-  </li>
-</ul>
-<p>
-
-</p>
-
-<h2 id="DesignForLargeScreens">Design for High-Density Large Screens</h2>
-
-<p>
-The common HDTV display resolutions are 720p, 1080i, and 1080p. Design your UI for 1080p, and then 
-allow the Android system to downscale your UI to 720p if necessary. In general, downscaling (removing pixels) 
-does not degrade the UI (Notice that the converse is not true; you should avoid upscaling because it degrades 
-UI quality).
-</p>
-
-<p>
-To get the best scaling results for images, provide them as <a href="{@docRoot}tools/help/draw9patch.html">
-9-patch image</a> elements if possible.
-If you provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or grainy. This 
-is not a good experience for the user. Instead, use high-quality images. 
-</p>
-
-<p>
-For more information on optimizing apps for large screens see <a href="{@docRoot}training/multiscreen/index.html">
-Designing for multiple screens</a>.
-</p>
-
-<h2 id="HandleLargeBitmaps">Design to Handle Large Bitmaps</h2>
-
-<p>
-The Android system has a limited amount of memory, so downloading and storing high-resolution images can often 
-cause out-of-memory errors in your app. To avoid this, follow these tips:
-</p>
-
-<ul>
-  <li>Load images only when they're displayed on the screen. For example, when displaying multiple images in 
-      a {@link android.widget.GridView} or 
-      {@link android.widget.Gallery}, only load an image when 
-      {@link android.widget.Adapter#getView(int, View, ViewGroup) getView()} 
-      is called on the View's {@link android.widget.Adapter}.
-  </li>
-  <li>Call {@link android.graphics.Bitmap#recycle()} on 
-      {@link android.graphics.Bitmap} views that are no longer needed.
-  </li>
-  <li>Use {@link java.lang.ref.WeakReference} for storing references 
-      to {@link android.graphics.Bitmap} objects in an in-memory 
-      {@link java.util.Collection}.</li>
-  <li>If you fetch images from the network, use {@link android.os.AsyncTask} 
-      to fetch them and store them on the SD card for faster access.
-      Never do network transactions on the application's UI thread.
-  </li>
-  <li>Scale down really large images to a more appropriate size as you download them; otherwise, downloading the image 
-  itself may cause an "Out of Memory" exception. Here is sample code that scales down images while downloading:
-  
-  <pre>
-  // Get the source image's dimensions
-  BitmapFactory.Options options = new BitmapFactory.Options();
-  // This does not download the actual image, just downloads headers.
-  options.inJustDecodeBounds = true; 
-  BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
-  // The actual width of the image.
-  int srcWidth = options.outWidth;  
-  // The actual height of the image.
-  int srcHeight = options.outHeight;  
-
-  // Only scale if the source is bigger than the width of the destination view.
-  if(desiredWidth > srcWidth)
-    desiredWidth = srcWidth;
-
-  // Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2.
-  int inSampleSize = 1;
-  while(srcWidth / 2 > desiredWidth){
-    srcWidth /= 2;
-    srcHeight /= 2;
-    inSampleSize *= 2;
-  }
-
-  float desiredScale = (float) desiredWidth / srcWidth;
-
-  // Decode with inSampleSize
-  options.inJustDecodeBounds = false;
-  options.inDither = false;
-  options.inSampleSize = inSampleSize;
-  options.inScaled = false;
-  // Ensures the image stays as a 32-bit ARGB_8888 image.
-  // This preserves image quality.
-  options.inPreferredConfig = Bitmap.Config.ARGB_8888;  
-                                                	
-  Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
-
-  // Resize
-  Matrix matrix = new Matrix();
-  matrix.postScale(desiredScale, desiredScale);
-  Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0,
-      sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
-  sampledSrcBitmap = null;
-
-  // Save
-  FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE);
-  scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
-  scaledBitmap = null;
-   </pre>
-  </li> </ul>
\ No newline at end of file
diff --git a/docs/html/training/tv/optimizing-navigation-tv.jd b/docs/html/training/tv/optimizing-navigation-tv.jd
deleted file mode 100644
index bb78258..0000000
--- a/docs/html/training/tv/optimizing-navigation-tv.jd
+++ /dev/null
@@ -1,206 +0,0 @@
-page.title=Optimizing Navigation for TV
-parent.title=Designing for TV
-parent.link=index.html
-
-trainingnavtop=true
-previous.title=Optimizing Layouts for TV
-previous.link=optimizing-layouts-tv.html
-next.title=Handling Features Not Supported on TV
-next.link=unsupported-features-tv.html
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
-  <li><a href="#HandleDpadNavigation">Handle D-pad Navigation</a></li>
-  <li><a href="#HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</a></li>
-  <li><a href="#DesignForEasyNavigation">Design for Easy Navigation</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
-  <li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
-</ul>
-
-</div>
-</div>
-
-<p>
-An important aspect of the user experience when operating a TV is the direct human interface: a remote control. 
-As you optimize your Android application for TVs, you should pay special attention to how the user actually navigates 
-around your application when using a remote control instead of a touchscreen.
-</p>
-<p>
-This lesson shows you how to optimize navigation for TV by:
-</p>
-
-<ul>
-  <li>Ensuring all layout controls are D-pad navigable.</li>
-  <li>Providing highly obvious feedback for UI navigation.</li>
-  <li>Placing layout controls for easy access.</li>
-</ul>
-
-<h2 id="HandleDpadNavigation">Handle D-pad Navigation</h2> 
-
-<p>
-On a TV, users navigate with controls on a TV remote, using either a D-pad or arrow keys. 
-This limits movement to up, down, left, and right. 
-To build a great TV-optimized app, you must provide a navigation scheme in which the user can 
-quickly learn how to navigate your app using the remote.
-</p>
-
-<p>
-When you design navigation for D-pad, follow these guidelines:
-</p>
-
-<ul>
-  <li>Ensure that the D-pad  can navigate to all the visible controls on the screen.</li>
-  <li>For scrolling lists with focus, D-pad up/down keys scroll the list and Enter key selects an item in the list. Ensure that users can 
-  select an element in the list and that the list still scrolls when an element is selected.</li> 
-  <li>Ensure that movement between controls is straightforward and predictable.</li>
-</ul>
-
-<p>
-Android usually handles navigation order between layout elements automatically, so you don't need to do anything extra. If the screen layout 
-makes navigation difficult, or if you want users to move through the layout in a specific way, you can set up explicit navigation for your 
-controls.  
-For example, for an {@code android.widget.EditText}, to define the next control to receive focus, use:
-<pre>
-&lt;EditText android:id="@+id/LastNameField" android:nextFocusDown="@+id/FirstNameField"\&gt;
-</pre>
-The following table lists all of the available navigation attributes:
-</p>
-
-<table>
-<tr>
-<th>Attribute</th>
-<th>Function</th>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusDown}</td>
-<td>Defines the next view to receive focus when the user navigates down.</td>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusLeft}</td>
-<td>Defines the next view to receive focus when the user navigates left.</td>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusRight}</td>
-<td>Defines the next view to receive focus when the user navigates right.</td>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusUp}</td>
-<td>Defines the next view to receive focus when the user navigates up.</td>
-</tr>
-</table>
-
-<p>
-To use one of these explicit navigation attributes, set the value to the ID (android:id value) of another widget in the layout. You should set 
-up the navigation order as a loop, so that the last control directs focus back to the first one.
-</p>
-
-<p>
-Note: You should only use these attributes to modify the navigation order if the default order that the system applies does not work well.
-</p>
-
-<h2 id="HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</h2>
-
-<p>
-Use appropriate color highlights for all navigable and selectable elements in the UI. This makes it easy for users to know whether the control 
-is currently focused or selected when they navigate with a D-pad. Also, use uniform highlight scheme across your application.
-</p>
-
-<p>
-Android provides <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">Drawable State List Resources</a> to implement highlights 
-for selected and focused controls. For example:
-</p>
-
-res/drawable/button.xml:
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;
-    &lt;item android:state_pressed="true"
-          android:drawable="@drawable/button_pressed" /&gt; &lt;!-- pressed --&gt;
-    &lt;item android:state_focused="true"
-          android:drawable="@drawable/button_focused" /&gt; &lt;!-- focused --&gt;
-    &lt;item android:state_hovered="true"
-          android:drawable="@drawable/button_focused" /&gt; &lt;!-- hovered --&gt;
-    &lt;item android:drawable="@drawable/button_normal" /&gt; &lt;!-- default --&gt;
-&lt;/selector&gt;
-</pre>
-
-<p>
-This layout XML applies the above state list drawable to a {@link android.widget.Button}:
-</p>
-<pre>
-&lt;Button
-    android:layout_height="wrap_content"
-    android:layout_width="wrap_content"
-    android:background="@drawable/button" /&gt;
-</pre>
-
-<p>
-Provide sufficient padding within the focusable and selectable controls so that the highlights around them are clearly visible. 
-</p>
-
-<h2 id="DesignForEasyNavigation">Design for Easy Navigation</h2>
-
-<p>
-Users should be able to navigate to any UI control with a couple of D-pad clicks. Navigation should be easy and  intuitive to 
-understand.  For any non-intuitive actions, provide users with written help, using a dialog triggered by a help button or action bar icon. 
-</p>
-
-<p>
-Predict the next screen that the user will want to navigate to and provide one click navigation to it. If the current screen UI is very sparse, 
-consider making it a multi pane screen. Use fragments for making multi-pane screens. For example, consider the multi-pane UI below with continent names 
-on the left and list of cool places in each continent on the right. 
-</p>
-
-<img src="{@docRoot}images/training/cool-places.png" alt="" />
-
-<p>
-The above UI consists of three Fragments - <code>left_side_action_controls</code>, <code>continents</code> and 
-<code>places</code> - as shown in its layout 
-xml file below. Such multi-pane UIs make D-pad navigation easier and make good use of the horizontal screen space for 
-TVs.
-</p>
-res/layout/cool_places.xml
-<pre>
-&lt;LinearLayout   
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal"
-   &gt;
-   &lt;fragment
-        android:id="@+id/left_side_action_controls"
-        android:layout_width="0px"
-        android:layout_height="match_parent"
-        android:layout_marginLeft="10dip"
-        android:layout_weight="0.2"/&gt;
-    &lt;fragment
-        android:id="@+id/continents"
-        android:layout_width="0px"
-        android:layout_height="match_parent"
-        android:layout_marginLeft="10dip"
-        android:layout_weight="0.2"/&gt;
-
-    &lt;fragment
-        android:id="@+id/places"
-        android:layout_width="0px"
-        android:layout_height="match_parent"
-        android:layout_marginLeft="10dip"
-        android:layout_weight="0.6"/&gt;
-
-&lt;/LinearLayout&gt;
-</pre>
-
-<p>
-Also, notice in the UI layout above action controls are on the left hand side of a vertically scrolling list to make 
-them easily accessible using D-pad. 
-In general, for layouts with horizontally scrolling components, place action controls on left or right hand side and 
-vice versa for vertically scrolling components.
-</p>
-
diff --git a/docs/html/training/tv/unsupported-features-tv.jd b/docs/html/training/tv/unsupported-features-tv.jd
deleted file mode 100644
index a9f090b..0000000
--- a/docs/html/training/tv/unsupported-features-tv.jd
+++ /dev/null
@@ -1,157 +0,0 @@
-page.title=Handling Features Not Supported on TV
-parent.title=Designing for TV
-parent.link=index.html
-
-trainingnavtop=true
-previous.title=Optimizing Navigation for TV
-previous.link=optimizing-navigation-tv.html
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
-  <li><a href="#WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</a></li>
-  <li><a href="#CheckAvailableFeatures">Check for Available Features at Runtime</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>
-TVs are much different from other Android-powered devices:
-</p>
-<ul>
-  <li>They're not mobile.</li>
-  <li>Out of habit, people use them for watching media with little or no interaction.</li>
-  <li>People interact with them from a distance.</li>
-</ul>
-
-<p>
-Because TVs have a different purpose from other devices, they usually don't have hardware features 
-that other Android-powered devices often have. For this reason, the Android system does not 
-support the following features for a TV device:
-<table>
-<tr>
-<th>Hardware</th>
-<th>Android feature descriptor</th>
-</tr>
-<tr>
-<td>Camera</td>
-<td>android.hardware.camera</td>
-</tr>
-<tr>
-<td>GPS</td>
-<td>android.hardware.location.gps</td>
-</tr>
-<tr>
-<td>Microphone</td>
-<td>android.hardware.microphone</td>
-</tr>
-<tr>
-<td>Near Field Communications (NFC)</td>
-<td>android.hardware.nfc</td>
-</tr>
-<tr>
-<td>Telephony</td>
-<td>android.hardware.telephony</td>
-</tr>
-<tr>
-<td>Touchscreen</td>
-<td>android.hardware.touchscreen</td>
-</tr>
-</table>
-</p>
-
-<p>
-This lesson shows you how to work around features that are not available on TV by:
-<ul>
-  <li>Providing work arounds for some non-supported features.</li>
-  <li>Checking for available features at runtime and conditionally activating/deactivating certain code 
-  paths based on availability of those features.</li>
-</ul>
-</p>
-
-
-<h2 id="WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</h2> 
-
-<p>
-Android doesn't support touchscreen interaction for TV devices, most TVs don't have touch screens, 
-and interacting with a TV using a touchscreen is not consistent with the 10 foot environment. For 
-these reasons, users interact with Android-powered TVs using a remote. In consideration of this, 
-ensure that every control in your app can be accessed with the D-pad. Refer back to the previous two lessons 
-<a href="{@docRoot}training/tv/optimizing-layouts-tv.html">Optimizing Layouts for TV</a> and 
-<a href="{@docRoot}training/tv/optimizing-navigation-tv.html">Optimize Navigation for TV</a> for
-more details 
-on this topic. The Android system assumes that a device has a touchscreen, so if you want your application 
-to run on a TV, you must <strong>explicitly</strong> disable the touchscreen requirement in your manifest file:
-<pre>
-&lt;uses-feature android:name="android.hardware.touchscreen" android:required="false"/&gt;
-</pre>
-</p> 
-
-<p>
-Although a TV doesn't have a camera, you can still provide a photography-related application on a TV. 
-For example, if you have an app that takes, views and edits photos, you can disable its picture-taking 
-functionality for TVs and still allow users to view and even edit photos. The next section talks about how to 
-deactivate or activate specific functions in the application based on runtime device type detection.
-</p>
-
-<p>
-Because TVs are stationary, indoor devices, they don't have built-in GPS. If your application uses location 
-information, allow users to search for a location or use a "static" location provider to get 
-a location from the zip code configured during the TV setup.
-<pre>
-LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-Location location = locationManager.getLastKnownLocation("static");
-Geocoder geocoder = new Geocoder(this);
-Address address = null;
-
-try {
-  address = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1).get(0);
-  Log.d("Zip code", address.getPostalCode());
-
-} catch (IOException e) {
-  Log.e(TAG, "Geocoder error", e);
-}
-</pre>
-</p>
-
-<p>
-TVs usually don't support microphones, but if you have an application that uses voice control, 
-you can create a mobile device app that takes voice input and then acts as a remote control for a TV.
-</p>
-
-<h2 id="CheckAvailableFeatures">Check for Available Features at Runtime</h2>
-
-<p>
-To check if a feature is available at runtime, call 
-{@link android.content.pm.PackageManager#hasSystemFeature(String)}.
- This method takes a single argument : a string corresponding to the 
-feature you want to check. For example, to check for touchscreen, use 
-{@link android.content.pm.PackageManager#hasSystemFeature(String)} with the argument 
-{@link android.content.pm.PackageManager#FEATURE_TOUCHSCREEN}.
-</p>
-
-<p>
-The following code snippet demonstrates how to detect device type at runtime based on supported features:
-
-<pre>
-// Check if android.hardware.telephony feature is available.
-if (getPackageManager().hasSystemFeature("android.hardware.telephony")) {
-   Log.d("Mobile Test", "Running on phone");
-// Check if android.hardware.touchscreen feature is available.
-} else if (getPackageManager().hasSystemFeature("android.hardware.touchscreen")) {
-   Log.d("Tablet Test", "Running on devices that don't support telphony but have a touchscreen.");
-} else {
-    Log.d("TV Test", "Running on a TV!");
-}
-</pre>
-</p>
-
-<p>
-This is just one example of using runtime checks to deactivate app functionality that depends on features 
-that aren't available on TVs.
-</p>
\ No newline at end of file
diff --git a/docs/html/tv/images/hero.jpg b/docs/html/tv/images/hero.jpg
new file mode 100644
index 0000000..c42a436
--- /dev/null
+++ b/docs/html/tv/images/hero.jpg
Binary files differ
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
new file mode 100644
index 0000000..e1cae8c
--- /dev/null
+++ b/docs/html/tv/index.jd
@@ -0,0 +1,262 @@
+page.title=Android TV
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.type=about
+
+
+@jd:body
+
+<style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+  display:none;
+}
+</style>
+
+<style>
+#footer {
+    display: none;
+}
+.content-footer {
+  display: none;
+}
+</style>
+
+
+<div class="landing-body-content">
+  <div class="landing-hero-container">
+
+    <div class="landing-section tv-hero">
+      <div class="landing-hero-scrim"></div>
+      <div class="landing-hero-wrap">
+        <div class="vertical-center-outer">
+          <div class="vertical-center-inner">
+
+            <div class="col-10">
+              <div class="landing-section-header">
+                <div class="landing-h1 hero">Android TV</div>
+                <div class="landing-subhead hero">Your apps on the big screen</div>
+                <div class="landing-hero-description">
+                  <p>Engage users from the comfort of their couches.
+                    Put your app on TV and bring everyone into
+                    the action.</p>
+                </div>
+
+              <div class="landing-body">
+                <a href="{@docRoot}preview/tv/index.html" class="landing-button landing-primary" style="margin-top: 40px;">
+                  Get Started
+                </a>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div> <!-- end .wrap -->
+      <div class="landing-scroll-down-affordance">
+        <a class="landing-down-arrow" href="#reimagine-your-app">
+          <img src="{@docRoot}wear/images/carrot.png" alt="Scroll down to read more">
+        </a>
+      </div>
+    </div> <!-- end .landing-section .landing-hero -->
+  </div> <!-- end .landing-hero-container -->
+
+    <div class="landing-rest-of-page">
+
+      <div class="landing-section landing-gray-background" id="reimagine-your-app">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Reimagine Your App</div>
+            <div class="landing-subhead">
+              Design your app to shine on the biggest screen in the house.
+            </div>
+          </div>
+
+
+          <div class="landing-body">
+            <div class="landing-breakout cols">
+
+              <div class="col-3-wide">
+                <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+                <p>Simple</p>
+                <p class="landing-small">
+                  Smooth, fast interactions are key to a successful TV app. Keep navigation simple
+                  and light. Bring your content forward to let users enjoy it with a minimum of
+                  fuss.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+                </p>
+              </div>
+
+              <div class="col-3-wide">
+                <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+                <p>Cinematic</p>
+                <p class="landing-small">
+                  What would your app look like if it were a film? Use movement, animation and sound to make your app into an experience.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+                </p>
+              </div>
+
+              <div class="col-3-wide">
+                <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+                <p>Beautiful</p>
+                <p class="landing-small">
+                  Apps on TV should be a pleasure to look at, as well as enjoyable to use. Use
+                  made-for-TV styles to make your app familiar and fun.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}design/tv/index.html">Learn about design for TV</a>
+                </p>
+              </div>
+            </div>
+
+          </div>
+        </div>  <!-- end .wrap -->
+      </div>  <!-- end .landing-section -->
+
+      <div class="landing-section" style="background-color:#f5f5f5">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Build to Entertain</div>
+            <div class="landing-subhead">
+              Android TV let's you engage your users in a new, shared environment.<br>
+              Find out how to get your app ready for it's big screen debut.
+            </div>
+          </div>
+
+
+          <div class="landing-body">
+            <div class="landing-breakout cols">
+
+              <div class="col-3-wide">
+                <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+                <p>Made for TV</p>
+                <p class="landing-small">
+                  Take advantage of pre-built fragments for browsing and interacting with media
+                  catalogs.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}design/tv/index.html">Learn pre-built fragments</a>
+                </p>
+              </div>
+
+              <div class="col-3-wide">
+                <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+                <p>Get Found</p>
+                <p class="landing-small">
+                  Give your content the attention it deserves by including it in Android TV's global
+                  search results.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+                </p>
+              </div>
+
+              <div class="col-3-wide">
+                <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+                <p>Recommend</p>
+                <p class="landing-small">
+                  Suggest content from your app to keep your users coming back.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}design/tv/index.html">Learn about design for TV</a>
+                </p>
+              </div>
+
+            </div>
+
+          </div>
+        </div>  <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+      <div class="landing-section landing-red-background">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1 landing-align-left">Get Started with Android TV</div>
+            <div class="landing-body">
+              <p>You can begin building apps right away using these developer resources.</p>
+            </div>
+          </div>
+
+          <div class="landing-body">
+            <div class="landing-breakout cols">
+              <div class="col-8">
+                <p>Preview SDK</p>
+                <p>
+                  Get started building for Android TV using the Android L-preview SDK. The preview
+                  SDK includes the Android TV emulator so you can start building your TV app right
+                  away.
+                </p>
+
+              </div>
+
+              <div class="col-8">
+                <p>ADT-1 Developer Kit</p>
+                <p>
+                  While supplies last, developers can request an ADT-1 Developer Kit, a compact and
+                  powerful streaming media player and gamepad, ideal for developing apps for Android
+                  TV.
+                </p>
+
+              </div>
+
+            </div>
+          </div>
+
+          <div class="landing-body">
+            <div class="landing-breakout cols">
+
+              <div class="col-8">
+                <a href="{@docRoot}preview/download.html" class="landing-button landing-secondary">
+                  Download the Preview SDK
+                </a>
+              </div>
+
+              <div class="col-8">
+                <a href="{@docRoot}tv/adt-1/request.html" class="landing-button landing-secondary">
+                  Request ADT-1 Developer Kit
+                </a>
+            </div>
+          </div>
+
+        </div>  <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
+
+    </div> <!-- end .landing-rest-of-page -->
+
+
+    <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
+      <div class="layout-content-col col-16" style="padding-top:4px">
+        <style>#___plusone_0 {float:right !important;}</style>
+        <div class="g-plusone" data-size="medium"></div>
+      </div>
+    </div>
+    <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+      <div id="copyright">
+        Except as noted, this content is
+        licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+        Creative Commons Attribution 2.5</a>. For details and
+        restrictions, see the <a href="/license.html">Content
+        License</a>.
+      </div>
+    </div>
+
+
+  </div> <!-- end landing-body-content -->
+
+  <script>
+  $("a.landing-down-arrow").on("click", function(e) {
+    $("body").animate({
+      scrollTop: $(".wear-hero").height() + 76
+    }, 1000, "easeOutQuint");
+    e.preventDefault();
+  });
+  </script>
diff --git a/docs/html/wear/css/wear.css b/docs/html/wear/css/wear.css
deleted file mode 100644
index fe9eef2..0000000
--- a/docs/html/wear/css/wear.css
+++ /dev/null
@@ -1,447 +0,0 @@
-/**
- * UTILITIES
- */
-
-
-.border-box {
-  box-sizing: border-box;
-}
-
-.vertical-center-outer {
-  display: table;
-  height: 100%;
-  width: 100%;
-}
-
-.vertical-center-inner {
-  display: table-cell;
-  vertical-align: middle;
-}
-
-/**
- * TYPE STYLES
- */
-
-.wear-h1 {
-  font-weight: 300;
-  font-size: 60px;
-  line-height: 78px;
-  text-align: center;
-  letter-spacing: -1px;
-}
-
-.wear-pre-h1 {
-  font-weight: 400;
-  font-size: 28px;
-  color: #93B73F;
-  line-height: 36px;
-  text-align: center;
-  letter-spacing: -1px;
-  text-transform: uppercase;
-
-}
-
-.wear-h1.hero {
-  text-align: left;
-}
-
-.wear-h2 {
-  font-weight: 300;
-  font-size: 42px;
-  line-height: 64px;
-  text-align: center;
-}
-
-
-.wear-subhead {
-  color: #999999;
-  font-size: 20px;
-  line-height: 28px;
-  text-align: center;
-}
-.wear-subhead.hero {
-  text-align: left;
-  color: white;
-}
-
-.wear-hero-description {
-  text-align: left;
-  margin: 1em 0;
-}
-
-.wear-hero-description p {
-  font-weight: 300;
-  margin: 0;
-  font-size: 18px;
-  line-height: 24px;
-}
-
-.wear-body .wear-small {
-  font-size: 14px;
-  line-height: 19px;
-}
-
-.wear-body.wear-align-center {
-  text-align: center;
-}
-
-.wear-align-left {
-  text-align: left;
-}
-
-/**
- * LAYOUT
- */
-
-#body-content,
-.fullpage,
-#jd-content,
-.jd-descr,
-.wear-body-content {
-  height: 100%;
-}
-
-.wear-section {
-  padding: 80px 10px 80px;
-  width: 100%;
-  margin-left: -10px;
-  text-rendering: optimizeLegibility;
-}
-
-#extending-android-to-wearables {
-  padding-top: 30px;
-}
-
-.wear-short-section {
-  padding: 40px 10px 28px;
-}
-
-.wear-gray-background {
-  background-color: #e9e9e9;
-}
-
-.wear-white-background {
-  background-color: white;
-}
-
-.wear-red-background {
-  color: white;
-  background-color: hsl(8, 70%, 54%);
-}
-
-.wear-subhead-red {
-  color: hsl(8, 71%, 84%);
-  text-align: left;
-}
-
-.wear-subhead-red p {
-  margin-top: 20px;
-}
-
-.wear-hero-container {
-  height: 100%;
-}
-
-.wear-hero {
-  height: calc(100% - 70px);
-  min-height: 504px;
-  margin-top: 0;
-  padding-top: 0;
-  padding-bottom: 0;
-  background-image: url(/wear/images/hero.jpg);
-  background-size: cover;
-  background-position: right center;
-  color: white;
-  position: relative;
-  overflow: hidden;
-}
-
-.wear-hero-scrim {
-  background: black;
-  opacity: .2;
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  margin-left: -10px;
-}
-
-.wear-hero-wrap {
-  margin: 0 auto;
-  width: 940px;
-  clear: both;
-  height: 100%;
-  position: relative;
-}
-
-.wear-section-header {
-  margin-bottom: 40px;
-}
-
-.wear-hero-wrap .wear-section-header {
-  margin-bottom: 16px;
-}
-
-.wear-body {
-  font-size: 18px;
-  line-height: 24px;
-}
-
-.wear-button {
-  white-space: nowrap;
-  display: inline-block;
-  padding: 16px 32px;
-  font-size: 18px;
-  font-weight: 500;
-  line-height: 24px;
-  cursor: pointer;
-  color: white;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-       -o-user-select: none;
-  user-select: none;
-  -webkit-transition: .2s background-color ease-in-out;
-     -moz-transition: .2s background-color ease-in-out;
-       -o-transition: .2s background-color ease-in-out;
-  transition: .2s background-color ease-in-out;
-}
-
-.wear-primary {
-  background-color: hsl(8, 70%, 54%); /* #dc4b35 */
-  color: #f8f8f8;
-}
-
-.wear-button.wear-primary:hover {
-  background-color: hsl(8, 70%, 44%); /* #bf3722 */
-}
-
-.wear-button.wear-primary:active {
-  background-color: hsl(8, 70%, 36%); /* # */
-}
-
-.wear-button.wear-secondary {
-  background-color: hsl(8, 70%, 44%);
-}
-
-.wear-button.wear-secondary:hover {
-  background-color: hsl(8, 70%, 36%);
-}
-
-.wear-button.wear-secondary:active {
-  background-color: hsl(8, 70%, 30%);
-}
-
-a.wear-button,
-a.wear-button:hover,
-a.wear-button:visited {
-  color: white !important;
-}
-
-.wear-video-link {
-  white-space: nowrap;
-  display: inline-block;
-  padding: 16px 32px 16px 82px;
-  font-size: 18px;
-  font-weight: 400;
-  line-height: 24px;
-  cursor: pointer;
-  color: hsla(0, 0%, 100%, .8);
-  -webkit-user-select: none;
-     -moz-user-select: none;
-       -o-user-select: none;
-  user-select: none;
-  -webkit-transition: .2s color ease-in-out;
-     -moz-transition: .2s color ease-in-out;
-       -o-transition: .2s color ease-in-out;
-  transition: .2s color ease-in-out;
-}
-
-.wear-video-link:before {
-  height: 64px;
-  width: 64px;
-  display: inline-block;
-  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAFuklEQVR42u2dXWgcVRSAV9LWtBBTTZVWUhNqEQtq1QeroDRKFRFsROqTYPuo+JCiIoJKFC0USqlUfCiowRcfrBgVUUElefAPkW5T8aeaGn9aRbFsjP0x2cx8PuRMvFxmdjeb2Z17Z8+B85DsZPbO+eaec3/OPSkABdXsVI2gABSAqgJQAKoKQAGoKgAFoKoAFICqAlAAqgpAAai6DqDRAiwDeoFtwB7gPaAInABKwKToCWAMeB/YDdwJrAWWNLh9+QMAXABsBQ4A3wFTwAxQBmaBAAhjNJDPy3L938BXwAvArUCHAkh+kCXAVcA+YBw4bRg7MngtkgTlDPA98CywHmhTAP8/xCbgVeAvMZZpwDQllN7xB/AysKGlAQAXAvuBkzW85UVgCBgENlfQQbmuWAXELPAnsAvoaikAQBtwh/j3coLhS2LIfqCzzu/plL8fkvvFgZiR4L2lHrfkHQBgpQTFUwmGnwC212v0KjC2y/3jQPwDPA+05xYAcBHwubx1YZzhC02QBBBRbxgBzssdAOBy4JgRZE0ZTPuNr7FHDCbEhqNAd24AAN0yUbID7QSwsZChABut3hANXY8Bq70HIMb/Ocb4w81+66v0hmGrN0QQ1ngLQJYRvpWHMWWo4KDIaMnuCcVKgdlZAGL8t2J8vpPGrwChDLyWBMFlAA8D0z4ZvwKEs8D93gCQEc9Jy/jFgkdizaRDGUSs8wXAu1bQLQE9ngHosWbPAXDQeQAypT9rBd3+gociyxi2K9riLABZUj5iuZ6RgsciM2OzFxw2A7JrAO6VwGtKTwpG+Anoy9AVmb3gDHCPcwCAFcChRox6jPu9CazMeFQUAKNRL3AJwE2yopjq228BQPZ/d2bcCyaBTa4BeNGa8Q6naIA4GQWubiKEYWvBbp8zAGQt5VfL/fQ3GEAkTzXDLVkjokA2k5a7AuA2GaLNj/tTfvhq0pQgbcwLQtlQusYVALtlzSR191MjADNI9zbJDZWBR10BMGr5/4GMADQ0SAMDlht62xUAxy0AmzMEEMnhtIO0ZF2YAH5wITd0hQw/5wE04M1bjDyXZpC2hqMlYGnWAHqBf40APOEYgChI35VSWyasWfGqrAH0WVkOIw4CSC1IG2tDoSy7XJE1gPs8ArDoIG0BmJGk30wBDHgGYFFBOgbAtqwB7GxxAHerC8rOBU0Dt2gQzjYIb8gawDor+6HVhqFdrkzEwhabiAVOTMSkUb+06FLEUVfWgj5q0cW4g64AeNo66ZLlcnTDNmesBN4y8KArAG6QU42ttCEzBVzpCoAO4EfLDeV5SzIEvgHaXdqUP2BlQud1Ux55zj2uZUX02cPRnKalRLmu17qYmPWF5YbymJgVAh8Ay5wCII3ZEZOYm6fURGT2u9X43Mnk3CDHybmfmRVYXExPv9nKEcpLejqSC3SjdY2TBzTesHqB7wc0onTEV2KucxLApXKkJy9HlAI5anuJFwCkYQ/EuCJfD+mdBnYkXOssgHY53un7MdVZ4CVgqVcADAhjMafkfTioHc14P04yvvMApIEXy5F/+7S8y6UKolPyR4BVVf7Wi2IdawwIPhTrmAW+rmZ8bwBIQ7vloXwoVzNWS6UUrwAYy9YfOlqwKZDkgneA5Qu4l3cly84F9sqGhislywLmaozuYoGFXr0DII1ukxP1hxJ6QzR7HqLxRfumZaRzXZ3f4XXZyi7gCeB3kqsnzs+kSb9s5XHgMeD8RTxDLgq3rmeuYuFvNYCoR8wqujNi+L3UWBcu9wAMt3QZ8LiMlk5RuU50teq6kcEDgTolveIRYHUQBOek1O5cFu/ukLz7/ZJgNSm+OirebWpgaPS7slxfAr4EngGuX8jopqUBxGzyrAVuB54EXgc+lV4yLhO8cfn5E+ZqUD8kBu9sQvv0Hzj4rmoEBaAAVBWAAlBVAApAVQEoAFUFoABUFYACUFUACkC1CfofXVRJocowZVYAAAAASUVORK5CYII=);
-  background-size: contain;
-  position: absolute;
-  content: "";
-  opacity: .7;
-  margin-top: -19px;
-  margin-left: -64px;
-  -webkit-transition: .2s opacity ease-in-out;
-     -moz-transition: .2s opacity ease-in-out;
-       -o-transition: .2s opacity ease-in-out;
-  transition: .2s opacity ease-in-out;
-}
-
-.wear-video-link:hover {
-  color: hsla(0, 0%, 100%, 1);
-}
-
-.wear-video-link:hover:before {
-  opacity: 1;
-}
-
-.wear-social-image {
-  float: left;
-  margin-right: 14px;
-  height: 64px;
-  width: 64px;
-}
-
-.wear-social-copy {
-  padding-left: 78px;
-}
-
-.wear-scroll-down-affordance {
-  position: absolute;
-  bottom: 0;
-  width: 100%;
-  text-align: center;
-  z-index: 10;
-}
-
-.wear-down-arrow {
-  padding: 24px;
-  display: inline-block;
-  opacity: .5;
-  -webkit-transition: .2s opacity ease-in-out;
-     -moz-transition: .2s opacity ease-in-out;
-       -o-transition: .2s opacity ease-in-out;
-  transition: .2s opacity ease-in-out;
-
-  -webkit-animation-name: pulse-opacity;
-  -webkit-animation-duration: 4s;
-}
-
-.wear-down-arrow:hover {
-  opacity: 1;
-}
-
-.wear-down-arrow img {
-  height: 28px;
-  width: 28px;
-  margin: 0 auto;
-  display: block;
-}
-
-.wear-divider {
-  display: inline-block;
-  height: 2px;
-  background-color: white;
-  position: relative;
-  margin: 10px 0;
-}
-
-/* 3 CLOLUMN LAYOUT */
-
-.wear-breakout {
-  margin-top: 40px;
-  margin-bottom: 40px;
-}
-
-.wear-breakout img {
-  margin-bottom: 20px;
-}
-
-.wear-partners img {
-  margin-bottom: 20px;
-}
-
-.wear-breakout p {
-  padding: 0 23px;
-}
-
-.wear-inset-video-container {
-  position: relative;
-}
-
-.wear-inset-video-container img.gif {
-  max-width: 222px;
-  position: absolute;
-  top: 40px;
-  left: 40px;
-}
-
-img.wear-bezel-only {
-  height:302px;
-  width:302px;
-}
-
-.wear-breakout.wear-partners img {
-  margin-bottom: 20px;
-}
-
-.col-3-wide {
-  display: inline;
-  float: left;
-  margin-left: 10px;
-  margin-right: 10px;
-}
-
-.col-3-wide {
-  width: 302px;
-}
-
-/**
- * ANIMATION
- */
-
-@-webkit-keyframes pulse-opacity {
-  0% {
-    opacity: .5;
-  }
-  20% {
-    opacity: .5;
-  }
-  40% {
-    opacity: 1;
-  }
-  60% {
-    opacity: .5;
-  }
-  80% {
-    opacity: 1;
-  }
-  100% {
-    opacity: .5;
-  }
-}
-
-
-
-/**
- * VIDEO
- */
-
-#video-container {
-  display:none;
-  position:fixed;
-  top:0;
-  left:-10px; 
-  width:102%;
-  height:100%;
-  background-color:rgba(0,0,0,0.7);
-  z-index:99;
-}
-
-#video-frame {
-  width:940px;
-  height:526.4px;
-  margin:80px auto 0;
-  display:none;
-}
-
-.video-close {
-cursor: pointer;
-position: relative;
-left: 940px;
-top: 0;
-pointer-events: all;
-}
-
-#icon-video-close {
-background-image: url("../images/close.png");
-background-position: 0 0;
-height: 36px;
-width: 36px;
-display:block;
-}
diff --git a/docs/html/wear/images/hero.jpg b/docs/html/wear/images/hero.jpg
index 40cc03c..7850a81 100644
--- a/docs/html/wear/images/hero.jpg
+++ b/docs/html/wear/images/hero.jpg
Binary files differ
diff --git a/docs/html/wear/images/kitchen_still.jpg b/docs/html/wear/images/kitchen_still.jpg
deleted file mode 100644
index 4afe359..0000000
--- a/docs/html/wear/images/kitchen_still.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 659e9f2..59d5506 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -2,7 +2,7 @@
 page.viewport_width=970
 fullpage=true
 no_footer_links=true
-page.customHeadTag=<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
+page.type=about
 
 @jd:body
 
@@ -14,8 +14,6 @@
 </style>
 
 
-
-
 <div id="video-container">
   <div id="video-frame">
     <div class="video-close">
@@ -23,28 +21,28 @@
     </div>
     <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
     <div id="ytapiplayer">
-      <a href="http://www.youtube.com/watch?v=0xQ3y902DEQ"><img width=940
-      src="https://i1.ytimg.com/vi/0xQ3y902DEQ/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+      <a href="http://www.youtube.com/watch?v=0xQ3y902DEQ"><img width="940" src="https://i1.ytimg.com/vi/0xQ3y902DEQ/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
     </div>
   </div>
 </div>
 
 
 
-<div class="wear-body-content">
-  <div class="wear-hero-container">
-    <div class="wear-section wear-hero">
-      <div class="wear-hero-scrim"></div>
-      <div class="wear-hero-wrap">
+<div class="landing-body-content">
+  <div class="landing-hero-container">
+    <div class="landing-section wear-hero">
+      <div class="landing-hero-scrim"></div>
+      <div class="landing-hero-wrap">
         <div class="vertical-center-outer">
           <div class="vertical-center-inner">
 
             <div class="col-10">
-              <div class="wear-section-header">
-                <div class="wear-h1 hero">Android Wear</div>
-                <div class="wear-subhead hero">Information that moves with you</div>
+              <div class="landing-section-header">
+                <div class="landing-h1 hero">Android Wear</div>
+                <div class="landing-subhead hero">Information that moves with you</div>
               </div>
-              <div class="wear-hero-description">
+              <div class="landing-hero-description">
+
                 <p>Small, powerful devices, worn on the body.
                 Useful information when you need it most.
                 Intelligent answers to spoken questions.
@@ -52,318 +50,208 @@
                 Your key to a multiscreen world.</p>
               </div>
 
-              <div class="wear-body">
-                <a href="/wear/preview/start.html" class="wear-button wear-primary" style="margin-top: 40px;">
-                  Get the Developer Preview
+              <div class="landing-body">
+                <a href="{@docRoot}training/building-wearables.html" class="landing-button landing-primary" style="margin-top: 40px;">
+                  Get Started
                 </a>
-                <a id="watchVideo" href="https://youtube.googleapis.com/v/0xQ3y902DEQ">
-                  <div class="wear-video-link">Watch the video</div>
-                </a>
-<script>
-$("#watchVideo").on("click", function(e) {
-  $("#video-container").fadeIn(400, function(){$("#video-frame").show()});
-
-  var params = { allowScriptAccess: "always"};
-  var atts = { id: "ytapiplayer" };
-  swfobject.embedSWF("//www.youtube.com/v/0xQ3y902DEQ?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1;autoplay=1",
-    "ytapiplayer", "940", "526.4", "8", null, null, params, atts);
-
-  e.preventDefault();
-});
-$("#icon-video-close").on("click", function() {
-  ytplayer = document.getElementById("ytapiplayer");
-  try {
-    ytplayer.stopVideo();
-    $(ytplayer).hide();
-    $("#video-container").fadeOut(400);
-  } catch(e) {
-    console.log('Video not available');
-    $("#video-container").fadeOut(400);
-  }
-});
-</script>
               </div>
             </div>
 
           </div>
         </div>
       </div> <!-- end .wrap -->
-      <div class="wear-scroll-down-affordance">
-        <a class="wear-down-arrow" href="#extending-android-to-wearables">
-          <img src="/wear/images/carrot.png" alt="Scroll down to read more">
+      <div class="landing-scroll-down-affordance">
+        <a class="landing-down-arrow" href="#extending-android-to-wearables">
+          <img src="{@docRoot}wear/images/carrot.png" alt="Scroll down to read more">
         </a>
       </div>
-    </div> <!-- end .wear-section .wear-hero -->
-  </div> <!-- end .wear-hero-container -->
+    </div> <!-- end .landing-section .landing-hero -->
+  </div> <!-- end .landing-hero-container -->
 
-    <div class="wear-rest-of-page">
-      <div class="wear-section" id="extending-android-to-wearables">
+    <div class="landing-rest-of-page">
+      <div class="landing-section" id="extending-android-to-wearables">
         <div class="wrap">
-          <div class="wear-section-header">
-            <div class="wear-h1">Extending Android to Wearables</div>
-            <div class="wear-subhead">
-              Android Wear extends the Android platform to a new generation of wearable devices. <br>
-              The user experience is designed specifically for wearables.
+          <div class="landing-section-header">
+            <div class="landing-h1">Extending Android to Wearables</div>
+            <div class="landing-subhead">
+              Android Wear extends the Android platform to a new generation of devices, <br>
+              with a user experience that's designed specifically for wearables.
+
             </div>
           </div>
 
-          <div class="wear-body">
-            <div class="wear-breakout cols">
+          <div class="landing-body">
+            <div class="landing-breakout cols">
               <div class="col-3-wide">
 
-                <div class="wear-inset-video-container">
-                  <img class="wear-bezel-only" src="/wear/images/screens/bezel.png" alt="">
-                  <img class="gif" src="/wear/images/screens/reservation_animated.gif">
+                <div class="landing-inset-video-container">
+                  <img class="landing-bezel-only" src="{@docRoot}wear/images/screens/bezel.png" alt="">
+                  <img class="gif" src="{@docRoot}wear/images/screens/reservation_animated.gif">
                 </div>
 
-                <p class="wear-small">
+                <p class="landing-small">
                   Say “Ok Google” to ask questions and get stuff done.
                 </p>
               </div>
               <div class="col-3-wide">
-                <img src="/wear/images/screens/circle_message2.png" itemprop="image" alt="" >
-                <p class="wear-small">
-                  Get glanceable, actionable information at just the right time throughout the day.
+                <img src="{@docRoot}wear/images/screens/circle_message2.png" itemprop="image" alt="">
+                <p class="landing-small">
+                  Get glanceable, actionable information at just the right time with notifications
+                  that are synced from your handheld device.
+
                 </p>
               </div>
               <div class="col-3-wide">
-                <img src="/wear/images/screens/fitness-24.png" alt="">
-                <p class="wear-small">
-                  A wide range of sensors is available to your applications, from accelerometers to heart rate monitors.
+                <img src="{@docRoot}wear/images/screens/fitness-24.png" alt="">
+                <p class="landing-small">
+                  Design apps that can access a wide range of sensors and other hardware
+                   directly on the wearable.
+
                 </p>
               </div>
             </div>
 
             <p>
-              The Android Wear Developer Preview lets you create wearable experiences for your existing Android apps and see how they will appear on square and round Android wearables.
-            </p>
-
-            <p>
-              Later this year, we’ll be launching the Android Wear SDK, enabling even more customized experiences.
-            </p>
-          </div>
-        </div>  <!-- end .wrap -->
-      </div>  <!-- end .wear-section -->
-
-      <div class="wear-section wear-gray-background">
-        <div class="wrap">
-          <div class="wear-section-header">
-            <div class="wear-h1">Developer Preview</div>
-            <div class="wear-subhead">
-              Your app’s notifications will already appear on Android wearables. <br>
-              With the new Android Wear APIs you can customize and extend those notifications.
-            </div>
-          </div>
-
-
-          <div class="wear-body">
-            <div class="wear-breakout cols">
-              <div class="col-3-wide">
-                <img src="images/screens/14_circle_voicereply.png" alt="">
-                <p>Receive Voice Replies</p>
-                <p class="wear-small">
-                  Add actions to your notifications to allow users to reply by voice or touch. The system delivers the text to your app on the phone.
-                </p>
-                <p class="wear-small">
-                  <a href="/wear/notifications/remote-input.html">Learn about input actions</a>
-                </p>
-              </div>
-              <div class="col-3-wide">
-
-
-                <div class="wear-inset-video-container">
-                  <img class="wear-bezel-only" src="/wear/images/screens/bezel.png" alt="">
-                  <img class="gif" src="/wear/images/screens/pages_animated.gif">
-                </div>
-
-                <p>Add Notification Pages</p>
-                <p class="wear-small">
-                  Add additional pages to your notification that are visible on the wearable device to provide detailed information on the wrist.
-                </p>
-                <p class="wear-small">
-                  <a href="/wear/notifications/pages.html">Learn about pages</a>
-                </p>
-              </div>
-              <div class="col-3-wide">
-                <img src="images/screens/11_stack_B.png" alt="">
-                <p>Stack Multiple Notifications</p>
-                <p class="wear-small">
-                  Your app should consolidate similar notifications. On a wearable, you can stack them together so the details for each are immediately available.
-                </p>
-                <p class="wear-small">
-                  <a href="/wear/notifications/stacks.html">Learn about stacks</a>
-                </p>
-              </div>
-            </div>
-
-            <p>
-              You can also trigger your notifications contextually using existing Android APIs.  For example, use <a href="{@docRoot}training/location/geofencing.html">geofences</a> to provide glanceable information to your users when they are at home, or use the <a href="{@docRoot}training/location/activity-recognition.html">activity detection APIs</a> to send messages to your users’ wrists while they are bicycling.
-            </p>
-
-            <p>See the <a href="{@docRoot}wear/design/index.html">Android Wear Developer Preview Design Principles</a> for more suggestions on creating great wearable experiences.</p>
+              Before you start building, check out the
+              <a href="{@docRoot}design/wear/index.html">Android Wear Design Principles</a>
+              to understand how to create great experiences for this exciting, new form factor.</p>
 
           </div>
         </div>  <!-- end .wrap -->
-      </div>  <!-- end .wear-section -->
+      </div>  <!-- end .landing-section -->
 
-      <div class="wear-section" style="background-color:#f5f5f5">
+      <div class="landing-section landing-gray-background">
         <div class="wrap">
-          <div class="wear-section-header">
-            <div class="wear-pre-h1">Coming soon</div>
-            <div class="wear-h1">The Android Wear SDK</div>
-            <div class="wear-subhead">
-              The Developer Preview is just the beginning for Android Wear.
+          <div class="landing-section-header">
+            <div class="landing-h1">Developing for Android Wear</div>
+            <div class="landing-subhead">
+             The Android Wear APIs are delivered in the Android v4 support library and Google Play services.
+             This lets Android handhelds, old and new, communicate with Android wearables.
             </div>
           </div>
 
-          <div class="wear-body">
-            <p>
-              In the coming months we’ll be launching new APIs and features for Android wearables to create even more unique experiences for the wrist:
-            </p>
-
-            <div class="wear-breakout cols">
+          <div class="landing-body">
+            <div class="landing-breakout cols">
               <div class="col-4">
-                <img src="/wear/images/features/ts1.png" alt="">
-                <p>Build Custom UI</p>
-                <p class="wear-small">
-                  Create custom card layouts and run activities directly on  wearables.
+                <img src="{@docRoot}wear/images/features/ts2.png" alt="">
+                <p>Synced Notifications</p>
+                <p class="landing-small">
+                  Notifications on handhelds can automatically sync to wearables, so design them
+                  with both devices in mind.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}training/wearables/notifications/index.html">Build notifications</a>
                 </p>
               </div>
               <div class="col-4">
-                <img src="/wear/images/features/ts2.png" alt="">
+                <img src="{@docRoot}wear/images/features/ts1.png" alt="">
+                <p>Wearable Apps</p>
+                <p class="landing-small">
+                  Create custom experiences with activities, services, sensors, and much
+                  more with the Android SDK.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}training/wearables/apps/index.html">Create wearable apps</a>
+
+                </p>
+              </div>
+              <div class="col-4">
+                <img src="{@docRoot}wear/images/features/ts2.png" alt="">
                 <p>Send Data</p>
-                <p class="wear-small">
-                  Send data and actions between a phone and a wearable with data replication APIs and RPCs.
+                <p class="landing-small">
+                  Send data and actions between handhelds and wearables with
+                  data replication APIs and RPCs.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}training/wearables/data-layer/index.html">Work with the Data Layer</a>
+
                 </p>
               </div>
               <div class="col-4">
-                <img src="/wear/images/features/ts3.png" alt="">
-                <p>Control Sensors</p>
-                <p class="wear-small">
-                  Gather sensor data and display it in real-time on Android wearables.
-                </p>
-              </div>
-              <div class="col-4">
-                <img src="/wear/images/features/ts4.png" alt="">
+                <img src="{@docRoot}wear/images/features/ts4.png" alt="">
                 <p>Voice Actions</p>
-                <p class="wear-small">
-                  Register your app to handle voice actions, like "Ok Google, take a note."
+                <p class="landing-small">
+                  Register your app to handle voice actions, like "Ok Google, take a&nbsp;note,"
+                  for a hands-free experience.
+                </p>
+                <p class="landing-small">
+                  <a href="{@docRoot}training/wearables/apps/voice-actions.html">Integrate voice actions</a>
                 </p>
               </div>
             </div>
-
           </div>
         </div> <!-- end .wrap -->
-      </div> <!-- end .wear-section -->
+      </div> <!-- end .landing-section -->
 
-      <div class="wear-section wear-white-background">
+      <div class="landing-section landing-red-background">
         <div class="wrap">
-          <div class="wear-section-header">
-            <div class="wear-h2">Building an Ecosystem</div>
-            <div class="wear-body wear-align-center">
-              <p class="wear-small">
-                We’re working with several partners to bring you watches powered by Android Wear later this year!
-              </p>
-            </div>
-          </div>
+          <div class="landing-section-header">
+            <div class="landing-h1 landing-align-left">Get Started with Android Wear</div>
 
-          <div class="wear-partners cols">
-            <div class="col-4">
-              <img src="/wear/images/partners/asus.png" alt="Asus">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/broadcom.png" alt="Broadcom">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/fossil.png" alt="Fossil">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/htc.png" alt="HTC">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/intel.png" alt="Intel">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/lg.png" alt="LG">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/mediatek.png" alt="Mediatek">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/mips.png" alt="MIPS">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/motorola.png" alt="Motorola">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm">
-            </div>
-            <div class="col-4">
-              <img src="/wear/images/partners/samsung.png" alt="Samsung">
+            <div class="landing-subhead landing-subhead-red">
+              <p>
+                Set up your development environment and start working with the APIs.
+                We’re excited about the experiences you'll create and can't
+                wait to see what you do next.</p>
             </div>
           </div>
-        </div> <!-- end .wrap -->
-      </div> <!-- end .wear-section -->
-
-      <div class="wear-section wear-red-background">
-        <div class="wrap">
-          <div class="wear-section-header">
-            <div class="wear-h1 wear-align-left">Start working with Android Wear</div>
-            <div class="wear-subhead wear-subhead-red">
-              <p>
-                Your app’s notifications will already appear on Android wearables. <br>
-                With the new Android Wear APIs, you can customize and extend those notifications.
-              </p>
-              <p>
-                We’re excited about wearables and the experiences developers can create with them. <br>
-                We can’t wait to see what you do next.</p>
-            </div>
-          </div>
-          <div class="wear-body">
-            <a href="/wear/preview/start.html" class="wear-button wear-secondary" style="margin-top: 20px;">
-              Get the Developer Preview
+          <div class="landing-body">
+            <a href="{@docRoot}training/building-wearables.html" class="landing-button landing-secondary" style="margin-top: 20px;">
+              Get Started
             </a>
           </div>
         </div>
       </div>
 
-      <div class="wear-section">
+      <div class="landing-section">
         <div class="wrap">
           <div class="cols">
-            <div class="wear-body">
+            <div class="landing-body">
               <div class="col-3-wide">
                   <a target="_blank" href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef">
-                    <img class="wear-social-image" src="//www.google.com/images/icons/product/youtube-128.png" alt="">
+                    <img class="landing-social-image" src="//www.google.com/images/icons/product/youtube-128.png" alt="">
                   </a>
-                <div class="wear-social-copy">
+                <div class="landing-social-copy">
                   <p>DevBytes</p>
-                  <p class="wear-small">
-                    Learn how to optimize your app notifications for wearable devices in this <a target="_blank" href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef">DevBytes video</a> using the Android Wear Developer Preview.
-                  </p>
+                    <p class="landing-small">
+                    Learn the basic concepts of Android Wear
+                    development with videos from the product team.
+                    </p>
+                    <br>
+                    <p class="landing-small">
+                      <a target="_blank" href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef">DevBytes videos</a>
+                    </p>
                 </div>
               </div>
               <div class="col-3-wide">
-                <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-wear-developer-preview.html">
-                  <img class="wear-social-image" src="/wear/images/blogger.png" alt="">
+                <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-landing-developer-preview.html">
+                  <img class="landing-social-image" src="{@docRoot}wear/images/blogger.png" alt="">
                 </a>
-                <div class="wear-social-copy">
+                <div class="landing-social-copy">
                   <p>Blog Post</p>
-                  <p class="wear-small">
-                    Read more about the Android Wear Developer Preview announcement
-                    at the <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-wear-developer-preview.html">Android Developers Blog</a>.
+                  <p class="landing-small">
+                    Read more about Android Wear development
+                    on our blog. Just search for "Android Wear".
+
                   </p>
+                  <br>
+                    <p class="landing-small">
+                    <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-wear-developer-preview.html">Android Developers Blog</a>
+                    </p>
+                  <p></p>
                 </div>
               </div>
               <div class="col-3-wide">
                 <a target="_blank" href="http://g.co/androidweardev">
-                  <img class="wear-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Wear Developers">
+                  <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Wear Developers">
                 </a>
-                <div class="wear-social-copy">
+                <div class="landing-social-copy">
                   <p>G+ Community</p>
-                  <p class="wear-small">
-                    Follow us on Google+ to stay up-to-date on Android Wear development and join the discussion!
+                  <p class="landing-small">
+                    Follow us on Google+ to stay up-to-date with Android Wear development and to join the discussion!
+
                   </p>
-                  <p class="wear-small">
+                  <p class="landing-small">
                     <a target="_blank" href="http://g.co/androidweardev">+Android Wear Developers</a>
                   </p>
                 </div>
@@ -371,14 +259,12 @@
             </div>
           </div>
         </div> <!-- end .wrap -->
-      </div> <!-- end .wear-section -->
-    </div> <!-- end .wear-rest-of-page -->
-
-
+      </div> <!-- end .landing-section -->
+    </div> <!-- end .landing-rest-of-page -->
     <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
       <div class="layout-content-col col-16" style="padding-top:4px">
         <style>#___plusone_0 {float:right !important;}</style>
-        <div class="g-plusone" data-size="medium"></div>
+        <div id="___plusone_0" style="text-indent: 0px; margin: 0px; padding: 0px; border-style: none; float: none; line-height: normal; font-size: 1px; vertical-align: baseline; display: inline-block; width: 90px; height: 20px; background: transparent;"><iframe frameborder="0" hspace="0" marginheight="0" marginwidth="0" scrolling="no" style="position: static; top: 0px; width: 90px; margin: 0px; border-style: none; left: 0px; visibility: visible; height: 20px;" tabindex="0" vspace="0" width="100%" id="I0_1402525433965" name="I0_1402525433965" src="https://apis.google.com/u/0/_/+1/fastbutton?usegapi=1&amp;size=medium&amp;origin=http%3A%2F%2Frobertly.mtv%3A8080&amp;url=http%3A%2F%2Frobertly.mtv%3A8080%2Fwear%2Findex.html&amp;gsrc=3p&amp;jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.QxHQHBkhz7M.O%2Fm%3D__features__%2Fam%3DUQ%2Frt%3Dj%2Fd%3D1%2Fz%3Dzcms%2Frs%3DAItRSTMLrMyRVKsu2FQoRingre3w1MT49A#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh%2Conload&amp;id=I0_1402525433965&amp;parent=http%3A%2F%2Frobertly.mtv%3A8080&amp;pfname=&amp;rpctoken=32453860" data-gapiattached="true" title="+1"></iframe></div>
       </div>
     </div>
     <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
@@ -386,20 +272,9 @@
         Except as noted, this content is
         licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
         Creative Commons Attribution 2.5</a>. For details and
-        restrictions, see the <a href="/license.html">Content
+        restrictions, see the <a href="{@docRoot}license.html">Content
         License</a>.
       </div>
     </div>
-
-
-  </div> <!-- end wear-body-content -->
-
-  <script>
-  $("a.wear-down-arrow").on("click", function(e) {
-    $("body").animate({
-      scrollTop: $(".wear-hero").height() + 76
-    }, 1000, "easeOutQuint");
-    e.preventDefault();
-  });
-  </script>
+  </div> <!-- end landing-body-content -->
 
diff --git a/docs/html/wear/license.jd b/docs/html/wear/license.jd
deleted file mode 100644
index b07dacf..0000000
--- a/docs/html/wear/license.jd
+++ /dev/null
@@ -1,142 +0,0 @@
-page.title=Developer Preview License Agreement
-
-@jd:body
-
-
-<div class="sdk-terms" style="height:auto;border:0;padding:0;width:700px">
-This is the Android Wear Developer Preview License Agreement.
-
-1. Introduction
-
-1.1 The Android Wear Developer Preview Kit (referred to in this License Agreement as the “Developer Preview” and specifically including the Android system files, packaged APIs, Developer Preview library files, and the Developer Preview companion app, if and when they are made available) is licensed to you subject to the terms of this License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your use of the Developer Preview.
-
-1.2 "Android Wear" means the Android Wear devices and the Android Wear software stack for use on Android Wear devices.
-
-1.3 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time.
-
-1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
-
-2. Accepting this License Agreement
-
-2.1 In order to use the Developer Preview, you must first agree to this License Agreement. You may not use the Developer Preview if you do not accept this License Agreement.
-
-2.2 By clicking to accept, you hereby agree to the terms of this License Agreement.
-
-2.3 You may not use the Developer Preview and may not accept the License Agreement if you are a person barred from receiving the Developer Preview under the laws of the United States or other countries including the country in which you are resident or from which you use the Developer Preview.
-
-2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the Developer Preview on behalf of your employer or other entity.
-
-3. Developer Preview License from Google
-
-3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, internal-use, non-assignable and non-exclusive license to use the Developer Preview solely to develop applications to run on the Android Wear platform for Android Wear devices.
-
-3.2 You agree that Google or third parties own all legal right, title and interest in and to the Developer Preview, including any Intellectual Property Rights that subsist in the Developer Preview. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
-
-3.3 You may not use the Developer Preview for any purpose not expressly permitted by this License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Developer Preview or any part of the Developer Preview; or (b) load any part of the Developer Preview onto a mobile handset or wearable computing device or any other hardware device except an Android Wear device, combine any part of the Developer Preview with other software, or distribute any software or device incorporating a part of the Developer Preview.
-
-3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android Wear, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the Developer Preview.
-
-3.5 Use, reproduction and distribution of components of the Developer Preview licensed under an open source software license are governed solely by the terms of that open source software license and not this License Agreement.
-
-3.6 You agree that the form and nature of the Developer Preview that Google provides may change without prior notice to you and that future versions of the Developer Preview may be incompatible with applications developed on previous versions of the Developer Preview. You agree that Google may stop (permanently or temporarily) providing the Developer Preview (or any features within the Developer Preview) to you or to users generally at Google's sole discretion, without prior notice to you.
-
-3.7 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
-
-3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Developer Preview.
-
-3.9 Your use of any Android system files, packaged APIs, or other components of the Developer Preview which are part of the Android Software Development Kit is subject to the terms of the Android Software Development Kit License Agreement located at http://developer.android.com/sdk/terms.html. These terms are hereby incorporated by reference into this License Agreement.
-
-4. Use of the Developer Preview by You
-
-4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement in or to any software applications that you develop using the Developer Preview, including any intellectual property rights that subsist in those applications.
-
-4.2 You agree to use the Developer Preview and write applications only for purposes that are permitted by (a) this License Agreement, (b) the Google Play Developer Program Policies located at https://play.google.com/about/developer-content-policy.html, and hereby incorporated into this License Agreement by reference), and (c) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries).  You agree to use reasonable efforts to comply with the Android Wear Platform Design Guide available on the Android Wear developer website
-
-4.3 You agree that if you use the Developer Preview to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so.
-
-4.4 You agree that you will not engage in any activity with the Developer Preview, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google.
-
-4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android Wear and/or applications for Android Wear, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
-
-4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
-
-4.7 Unless otherwise specified in writing by Google, Google does not intend use of Android Wear to create obligations under the Health Insurance Portability and Accountability Act, as amended, (“HIPAA”), and makes no representations that Android Wear satisfies HIPAA requirements. If you are (or become) a Covered Entity or Business Associate under HIPAA, you agree not to use Android Wear for any purpose or in any manner involving Protected Health Information unless you have received prior written consent to such use from Google.
-
-4.8 The Developer Preview is in development, and your testing and feedback are an important part of the development process. By using the Developer Preview, you acknowledge that implementation of some features are still under development and that you should not rely on the Developer Preview, Android Wear devices, Android Wear system software, or Android Wear services having the full functionality of a stable release. You agree not to publicly distribute or ship any application using this Developer Preview as this Developer Preview will no longer be supported after the official SDK is released.
-
-5. Your Developer Credentials
-
-5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
-
-6. Privacy and Information
-
-6.1 In order to continually innovate and improve the Developer Preview, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the Developer Preview are being used and how they are being used. Before any of this information is collected, the Developer Preview will notify you and seek your consent. If you withhold consent, the information will not be collected.
-
-6.2 The data collected is examined in the aggregate to improve the Developer Preview and is maintained in accordance with Google's Privacy Policy lcoated at http://www.google.com/policies/privacy/.
-
-7. Third Party Applications
-
-7.1 If you use the Developer Preview to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
-
-7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
-
-7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal relationship with these third parties.
-
-8. Using Google APIs
-
-8.1 Google APIs
-
-8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service.
-
-8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
-
-9. Terminating this License Agreement
-
-9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
-
-9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the Developer Preview and any relevant developer credentials.
-
-9.3 Google may at any time, terminate this License Agreement with you if:
-(A) you have breached any provision of this License Agreement; or
-(B) Google is required to do so by law; or
-(C) the partner with whom Google offered certain parts of Developer Preview (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the Developer Preview to you; or
-(D) Google decides to no longer provide the Developer Preview or certain parts of the Developer Preview to users in the country in which you are resident or from which you use the service, or the provision of the Developer Preview or certain Developer Preview services to you by Google is, in Google's sole discretion, no longer commercially viable.
-
-9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
-
-10. DISCLAIMER OF WARRANTIES
-
-10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE DEVELOPER PREVIEW IS AT YOUR SOLE RISK AND THAT THE DEVELOPER PREVIEW IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
-
-10.2 YOUR USE OF THE DEVELOPER PREVIEW AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE DEVELOPER PREVIEW IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
-
-10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-
-11. LIMITATION OF LIABILITY
-
-11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
-
-12. Indemnification
-
-12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys’ fees) arising out of or accruing from (a) your use of the Developer Preview, (b) any application you develop on the Developer Preview that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License Agreement.
-
-13. Changes to the License Agreement
-
-13.1 Google may make changes to the License Agreement as it distributes new versions of the Developer Preview. When these changes are made, Google will make a new version of the License Agreement available on the website where the Developer Preview is made available.
-
-14. General Legal Terms
-
-14.1 This License Agreement constitutes the whole legal agreement between you and Google and governs your use of the Developer Preview (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the Developer Preview.
-
-14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
-
-14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
-
-14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this License Agreement.
-
-14.5 EXPORT RESTRICTIONS. THE DEVELOPER PREVIEW IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE DEVELOPER PREVIEW. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
-
-14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under this License Agreement without the prior written approval of the other party.
-
-14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
-</div>
diff --git a/docs/html/wear/preview/signup.jd b/docs/html/wear/preview/signup.jd
deleted file mode 100644
index 8e8ec9a..0000000
--- a/docs/html/wear/preview/signup.jd
+++ /dev/null
@@ -1,169 +0,0 @@
-page.title=Sign Up for the Developer Preview
-
-@jd:body
-
-<p>To get started with the Android Wear Developer Preview, you must agree to the
-  following terms and conditions and provide the email address for your Google account.
-After signing up, you’ll have access to:</p>
-<ul>
-  <li>New APIs that allow you to build enhanced notifications for wearables.</li>
-  <li>Sample code using the new APIs.</li>
-  <li>The Android Wear Preview app that delivers your notifications to the Android Wear emulator.</li>
-</ul>
-
-<div class="sdk-terms" style="width:678px" onfocus="this.blur()"><div class="sdk-terms-padding">
-This is the Android Wear Developer Preview License Agreement.
-
-1. Introduction
-
-1.1 The Android Wear Developer Preview Kit (referred to in this License Agreement as the “Developer Preview” and specifically including the Android system files, packaged APIs, Developer Preview library files, and the Developer Preview companion app, if and when they are made available) is licensed to you subject to the terms of this License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your use of the Developer Preview.
-
-1.2 "Android Wear" means the Android Wear devices and the Android Wear software stack for use on Android Wear devices.
-
-1.3 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time.
-
-1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
-
-2. Accepting this License Agreement
-
-2.1 In order to use the Developer Preview, you must first agree to this License Agreement. You may not use the Developer Preview if you do not accept this License Agreement.
-
-2.2 By clicking to accept, you hereby agree to the terms of this License Agreement.
-
-2.3 You may not use the Developer Preview and may not accept the License Agreement if you are a person barred from receiving the Developer Preview under the laws of the United States or other countries including the country in which you are resident or from which you use the Developer Preview.
-
-2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the Developer Preview on behalf of your employer or other entity.
-
-3. Developer Preview License from Google
-
-3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, internal-use, non-assignable and non-exclusive license to use the Developer Preview solely to develop applications to run on the Android Wear platform for Android Wear devices.
-
-3.2 You agree that Google or third parties own all legal right, title and interest in and to the Developer Preview, including any Intellectual Property Rights that subsist in the Developer Preview. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
-
-3.3 You may not use the Developer Preview for any purpose not expressly permitted by this License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Developer Preview or any part of the Developer Preview; or (b) load any part of the Developer Preview onto a mobile handset or wearable computing device or any other hardware device except an Android Wear device, combine any part of the Developer Preview with other software, or distribute any software or device incorporating a part of the Developer Preview.
-
-3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android Wear, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the Developer Preview.
-
-3.5 Use, reproduction and distribution of components of the Developer Preview licensed under an open source software license are governed solely by the terms of that open source software license and not this License Agreement.
-
-3.6 You agree that the form and nature of the Developer Preview that Google provides may change without prior notice to you and that future versions of the Developer Preview may be incompatible with applications developed on previous versions of the Developer Preview. You agree that Google may stop (permanently or temporarily) providing the Developer Preview (or any features within the Developer Preview) to you or to users generally at Google's sole discretion, without prior notice to you.
-
-3.7 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
-
-3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Developer Preview.
-
-3.9 Your use of any Android system files, packaged APIs, or other components of the Developer Preview which are part of the Android Software Development Kit is subject to the terms of the Android Software Development Kit License Agreement located at http://developer.android.com/sdk/terms.html. These terms are hereby incorporated by reference into this License Agreement.
-
-4. Use of the Developer Preview by You
-
-4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement in or to any software applications that you develop using the Developer Preview, including any intellectual property rights that subsist in those applications.
-
-4.2 You agree to use the Developer Preview and write applications only for purposes that are permitted by (a) this License Agreement, (b) the Google Play Developer Program Policies located at https://play.google.com/about/developer-content-policy.html, and hereby incorporated into this License Agreement by reference), and (c) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries).  You agree to use reasonable efforts to comply with the Android Wear Platform Design Guide available on the Android Wear developer website
-
-4.3 You agree that if you use the Developer Preview to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so.
-
-4.4 You agree that you will not engage in any activity with the Developer Preview, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google.
-
-4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android Wear and/or applications for Android Wear, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
-
-4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
-
-4.7 Unless otherwise specified in writing by Google, Google does not intend use of Android Wear to create obligations under the Health Insurance Portability and Accountability Act, as amended, (“HIPAA”), and makes no representations that Android Wear satisfies HIPAA requirements. If you are (or become) a Covered Entity or Business Associate under HIPAA, you agree not to use Android Wear for any purpose or in any manner involving Protected Health Information unless you have received prior written consent to such use from Google.
-
-4.8 The Developer Preview is in development, and your testing and feedback are an important part of the development process. By using the Developer Preview, you acknowledge that implementation of some features are still under development and that you should not rely on the Developer Preview, Android Wear devices, Android Wear system software, or Android Wear services having the full functionality of a stable release. You agree not to publicly distribute or ship any application using this Developer Preview as this Developer Preview will no longer be supported after the official SDK is released.
-
-5. Your Developer Credentials
-
-5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
-
-6. Privacy and Information
-
-6.1 In order to continually innovate and improve the Developer Preview, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the Developer Preview are being used and how they are being used. Before any of this information is collected, the Developer Preview will notify you and seek your consent. If you withhold consent, the information will not be collected.
-
-6.2 The data collected is examined in the aggregate to improve the Developer Preview and is maintained in accordance with Google's Privacy Policy lcoated at http://www.google.com/policies/privacy/.
-
-7. Third Party Applications
-
-7.1 If you use the Developer Preview to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
-
-7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
-
-7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal relationship with these third parties.
-
-8. Using Google APIs
-
-8.1 Google APIs
-
-8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service.
-
-8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
-
-9. Terminating this License Agreement
-
-9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
-
-9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the Developer Preview and any relevant developer credentials.
-
-9.3 Google may at any time, terminate this License Agreement with you if:
-(A) you have breached any provision of this License Agreement; or
-(B) Google is required to do so by law; or
-(C) the partner with whom Google offered certain parts of Developer Preview (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the Developer Preview to you; or
-(D) Google decides to no longer provide the Developer Preview or certain parts of the Developer Preview to users in the country in which you are resident or from which you use the service, or the provision of the Developer Preview or certain Developer Preview services to you by Google is, in Google's sole discretion, no longer commercially viable.
-
-9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
-
-10. DISCLAIMER OF WARRANTIES
-
-10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE DEVELOPER PREVIEW IS AT YOUR SOLE RISK AND THAT THE DEVELOPER PREVIEW IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
-
-10.2 YOUR USE OF THE DEVELOPER PREVIEW AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE DEVELOPER PREVIEW IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
-
-10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-
-11. LIMITATION OF LIABILITY
-
-11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
-
-12. Indemnification
-
-12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys’ fees) arising out of or accruing from (a) your use of the Developer Preview, (b) any application you develop on the Developer Preview that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License Agreement.
-
-13. Changes to the License Agreement
-
-13.1 Google may make changes to the License Agreement as it distributes new versions of the Developer Preview. When these changes are made, Google will make a new version of the License Agreement available on the website where the Developer Preview is made available.
-
-14. General Legal Terms
-
-14.1 This License Agreement constitutes the whole legal agreement between you and Google and governs your use of the Developer Preview (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the Developer Preview.
-
-14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
-
-14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
-
-14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this License Agreement.
-
-14.5 EXPORT RESTRICTIONS. THE DEVELOPER PREVIEW IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE DEVELOPER PREVIEW. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
-
-14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under this License Agreement without the prior written approval of the other party.
-
-14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
-
-
-</div></div>
-
-
-<p class="caution">
-  <strong>Important:</strong> Your email address is used to provide your Google account
-  access to the Android Wear Preview app Beta Preview on Google Play Store. As such, the
-  email address you provide below must be for the account you use to download apps on Google Play Store.
-  We may also use your email address to provide you with updates about the Android Wear
-  platform release.
-</p>
-
-<iframe src="https://docs.google.com/forms/d/1iSJ084kEkV242cZisNMnj6G8qpi9r_zdEyfXA-hB1ao/viewform?embedded=true" width="100%" height="540" frameborder="0" marginheight="0" marginwidth="0" id="signupform">Loading...</iframe>
-
-
-
-
-</body>
-</html>
diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd
deleted file mode 100644
index f8f0129..0000000
--- a/docs/html/wear/preview/start.jd
+++ /dev/null
@@ -1,254 +0,0 @@
-page.title=Get Started with the Developer Preview
-
-@jd:body
-
-
-<div class="cols">
-
-  <div class="col-5">
-<p>The Android Wear Developer Preview includes tools and APIs that allow you to
-enhance your app notifications
-to provide an optimized user experience on Android wearables.</p>
-
-<p>With the Android Wear Developer Preview, you can:</p>
-
-<ul>
-  <li>Run the Android Wear platform in the Android emulator.</li>
-  <li>Connect your Android device to the emulator and view notifications from the
-device as cards on Android Wear.</li>
-  <li>Try new APIs in the preview support library that enhance your app's notifications
-with features such as voice replies and notification pages.</li>
-</ul>
-
-<p>To get access to the Developer Preview tools,
-click the sign up button on the right, then follow the setup instructions below.</p>
-  </div>
-
-  <div class="col-7">
-<img src="/wear/images/laptop-bridge.png" width="400" height="222" alt="" />
-
-<a href="/wear/preview/signup.html" class="button" style="
-    width: 370px;
-    margin: 10px 0 20px;
-    font-weight: bold;
-    font-size: 16px;
-">Sign Up for the Developer Preview</a>
-
-<p>Signing up provides you access to:</p>
-<ul>
-<li>New notification APIs in the preview support library.</li>
-<li>Sample apps using the new notification APIs.</li>
-<li>The <em>Android Wear Preview</em> app for your mobile device, which connects
-your device to the Android Wear emulator.</li>
-</ul>
-
-  </div>
-</div>
-
-
-<p class="caution"><strong>Caution:</strong>
-The current Android Wear Developer Preview is intended for <b>development and testing purposes only</b>, not for production apps. Google may change this Developer Preview significantly prior to the official release of the Android Wear SDK. You may not publicly distribute or ship any application using this Developer Preview, as this Developer Preview will no longer be supported after the official SDK is released (which will cause applications based only on the Developer Preview to break).</p>
-
-
-
-
-<h2 id="Prereq">Prerequisites</h2>
-
-<p>Before you begin the setup, you must:</p>
-
-<ol>
-  <li><a href="{@docRoot}sdk/index.html"><b>Install the Android SDK</b></a>.
-  <p>The Android SDK includes all the developer tools required to build
-apps for Android (optional IDEs are also available for download).</p></li>
-  <li><a href="{@docRoot}wear/preview/signup.html"><b>Sign up for the Android Wear Developer Preview</b></a>.
-  <p>You must sign up with a Gmail or other Google account in order to download the
-preview support library and receive access to the
-<em>Android Wear Preview</em> beta app on Google Play Store.</p></li>
-</ol>
-
-<p class="note"><strong>Note:</strong>
-If you're using the ADT plugin for Eclipse, you must update to version 22.6.1 or higher.
-If you're using Android Studio, you must update to version 0.5.1 or higher</p>
-
-
-
-<h2 id="Install">1. Install the Android Wear System Image</h2>
-
-
-<ol>
-  <li>Launch <a href="{@docRoot}tools/help/sdk-manager.html"
-    >Android SDK Manager</a>.
-  <ul>
-    <li>From Eclipse, select <b>Window > Android SDK Manager</b>.</li>
-    <li>From Android Studio, select <b>Tools > Android > SDK Manager</b>.</li>
-  </ul>
-  </li>
-  <li>Below Tools, verify that you have Android SDK Tools revision 22.6 or higher.
-    <p>If your version of Android SDK Tools is lower than 22.6, you must update:</p>
-    <ol>
-      <li>Select <strong>Android SDK Tools</strong>.</li>
-      <li>Click <strong>Install package</strong>.</li>
-      <li>Accept the license and click <strong>Install</strong>.</li>
-      <li>When the installation completes, restart Android SDK Manager.</li>
-    </ol>
-  </li>
-
-  <li>Below Android 4.4.2, select <strong>Android Wear ARM EABI v7a System Image</strong>.
-<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
-</p></li>
-  <li>Below Extras, ensure that you have the latest version of the
-<a href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
-    If an update is available, select <strong>Android Support Library</strong>. If you're using Android Studio, also select <strong>Android Support Repository</strong>.</li>
-  <li>Click <strong>Install packages</strong>.</li>
-  <li>Accept the license and click <strong>Install</strong>.</li>
-</ol>
-
-
-
-<h2 id="SetupEmulator">2. Set Up the Android Wear Emulator</h2>
-
-<ol>
-<li>Launch the <a href="{@docRoot}tools/help/avd-manager.html"
-  >Android Virtual Device Manager</a>.
-<ul>
-<li>From Eclipse, select <b>Window > Android Virtual Device Manager</b>.</li>
-<li>From Android Studio, select <b>Tools > Android > AVD Manager</b>.</li>
-</ul>
-</li>
-<li>Click <strong>New</strong>.</li>
-<li>For the AVD Name, enter "AndroidWearSquare" or "AndroidWearRound", depending on whether
-you want to create an emulator with a square or round display.</li>
-<li>For the Device, select <strong>Android Wear Square</strong> or
-	<strong>Android Wear Round</strong>.</li>
-<li>For the Target, select <strong>Android 4.4.2 - API Level 19</strong> (or higher).</li>
-<li>For the CPU/ABI, select <strong>Android Wear ARM (armeabi-v7a)</strong>.
-<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
-</p></li>
-<li>For the Skin, select <strong>AndroidWearSquare</strong> or
-<strong>AndroidWearRound</strong>.</li>
-<li>Leave all other options set to their defaults and click <strong>OK</strong>.
-  <p>Although real Android wearables do not provide a keyboard as an input method,
-    you should keep <strong>Hardware keyboard present</strong> selected so you can
-    provide text input on screens where users will instead provide voice input.</p>
-</li>
-<!--
-<li>Click <strong>Device Definitions</strong>.</li>
-<li>Select <strong>Android WearSquare</strong> then click <strong>Create AVD</strong>.</li>
-<li>Click <strong>OK</strong>.</li>
--->
-<li>In the list of AVDs, select the one you just created and click
- <strong>Start</strong>. In the following window, click <strong>Launch</strong>.</li>
-</ol>
-
-<p>The Android Wear emulator now starts. To begin testing your app's notifications,
-you must now pair the emulator to your development device
-that has the <em>Android Wear Preview</em> app installed.</p>
-
-<p class="note"><strong>Tip:</strong> To improve the emulator startup time, edit your AVD
-and enable <strong>Snapshot</strong> under Emulator Options. When you start the emulator,
-select <strong>Save to snapshot</strong> then click <strong>Launch</strong>. Once the emulator
-is running, close it to save a snapshot of the system.
-Start the AVD again, but select <strong>Launch from snapshot</strong> and
-deselect <strong>Save to snapshot</strong>.</p>
-
-<p class="caution"><strong>Caution:</strong> Do not install apps on the Android Wear emulator.
-The system does not support traditional Android apps and the result of running such apps is
-unpredictable.</p>
-
-
-
-<h2 id="SetupApp">3. Set Up the Android Wear Preview App</h2>
-
-<p>To view your app's notifications on the Android Wear emulator, you must have the
-<em>Android Wear Preview</em> app installed on your Android device (a phone or tablet).</p>
-
-<p>To receive the Android Wear Preview app, you must <a
-href="{@docRoot}wear/preview/signup.html">sign up for the Developer Preview</a> using the same
-Gmail or Google account you use with Google Play Store.</p>
-</p>
-
-<p class="note"><strong>Note:</strong> The <em>Android Wear Preview</em> app is compatible with
-    Android 4.3 and higher and is not available for the Android emulator.</p>
-
-<p>After you've signed up for the Developer Preview,
-  you'll receive a confirmation email that includes a link to opt-in to the
-  <em>Android Wear Preview</em> app beta program. Once you opt-in, it may take up to 24 hours for the
-  app to become available in Google Play Store.</p>
-
-<p>After you install the <em>Android Wear Preview</em> app, you can set up
-  your device to communicate with the Android Wear emulator:</p>
-
-<ol>
-<li>Open the <em>Android Wear Preview</em> app. You should see a notice that the app is currently
-  not enabled as a notification listener. Tap the message to open the system settings,
-  then select Android Wear Preview to grant it notification access.</li>
-<li>Connect your device to your development machine over USB. Be sure that no other
- Android devices are connected to the machine.</li>
-<li>Ensure that the Android Wear emulator (created in the previous section) is running.
-The emulator should show the time and an icon that indicates no device is connected.</li>
-<li>Open a command line terminal, navigate to your Android SDK's <code>platform-tools/</code>
-directory, then execute:
-<pre style="margin-top:.5em">adb -d forward tcp:5601 tcp:5601</pre>
-<p class="note"><strong>Note:</strong> You must execute this command each time you connect your
-device over USB.</p>
-</li>
-<li>Return to the Android Wear Preview app. It should now indicate that it is connected to
-  the emulator. The Android Wear emulator should now show the 'g' orb icon, indicating
-  that is is connected to your device.
-</ol>
-
-<p>Now, notifications from your device also appear in the Android Wear emulator.</p>
-
-
-
-
-<h2 id="AddLibrary">4. Add the Support Library to Your Project</h2>
-
-<p>The Android Wear preview support library includes several APIs that allow you to
-optimize your app's notifications for the Android Wear user experience.</p>
-
-<p>To receive the preview support library, you must <a
-href="{@docRoot}wear/preview/signup.html">sign up for the Developer Preview</a>. The
-confirmation email you receive after you sign up includes a link to download a ZIP file,
-which contains the preview support library and some sample apps.</p>
-
-<p>After you download and unzip the package, add the preview support library
-sto your Android project:</p>
-
-<p><b>If you're using Eclipse:</b></p>
-    <ol>
-      <li>In your Android app project, create a <code>libs/</code> directory in your project root
-    (the same location as the <code>AndroidManifest.xml</code> file).</li>
-      <li>Copy the v4 support library JAR file from your Android SDK directory (e.g.,
-        <code>&lt;sdk&gt;/extras/android/support/v4/android-support-v4.jar</code>) into your
-        project <code>libs/</code> directory.
-      <li>Also save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
-      <li>Right click each JAR file and select <strong>Build Path &gt; Add to Build Path</strong>.</li>
-    </ol>
-
- <p><b>If you're using Android Studio:</b></p>
-    <ol>
-     <li>In your Android app project, create a <code>libs/</code> directory in your project root
-    (the same location as the <code>AndroidManifest.xml</code> file).</li>
-      <li>Save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
-      <li>Open the <code>build.gradle</code> file in your app module.</li>
-      <li>Add a dependency rule for both the v4 support library and the Android Wear
-      preview support library:
-<pre>
-dependencies {
-    compile "com.android.support:support-v4:18.0.+"
-    compile files('../libs/wearable-preview-support.jar')
-}
-</pre>
-      </li>
-      <li>Click <strong>Sync Project with Gradle Files</strong> in the toolbar.</li>
-    </ol>
-
-<p>To start optimizing your notifications for Android Wear,
-  read <a href="{@docRoot}wear/notifications/creating.html"
-  >Creating Notifications for Android Wear</a>.</p>
-
-
-
-</body>
-</html>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 06cf253..ef0a411 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -194,6 +194,11 @@
      * while {@link #getAllocationByteCount()} will reflect that of the initial
      * configuration.</p>
      *
+     * <p>Note: This may change this result of hasAlpha(). When converting to 565,
+     * the new bitmap will always be considered opaque. When converting from 565,
+     * the new bitmap will be considered non-opaque, and will respect the value
+     * set by setPremultiplied().</p>
+     *
      * <p>WARNING: This method should NOT be called on a bitmap currently used
      * by the view system. It does not make guarantees about how the underlying
      * pixel buffer is remapped to the new config, just that the allocation is
@@ -217,7 +222,8 @@
             throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
         }
 
-        nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length);
+        nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+                mIsPremultiplied);
         mWidth = width;
         mHeight = height;
     }
@@ -1586,7 +1592,8 @@
     private static native void nativeDestructor(long nativeBitmap);
     private static native boolean nativeRecycle(long nativeBitmap);
     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
-                                                 int config, int allocSize);
+                                                 int config, int allocSize,
+                                                 boolean isPremultiplied);
 
     private static native boolean nativeCompress(long nativeBitmap, int format,
                                             int quality, OutputStream stream,
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 13789ca..158801c 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -65,11 +65,11 @@
 
     /**
      * Used to determine when compatibility scaling is in effect.
-     * 
+     *
      * @hide
      */
     protected int mScreenDensity = Bitmap.DENSITY_NONE;
-    
+
     // Used by native code
     @SuppressWarnings("UnusedDeclaration")
     private int mSurfaceFormat;
@@ -79,7 +79,7 @@
      * @hide
      */
     public static final int DIRECTION_LTR = 0;
-    
+
     /**
      * Flag for drawTextRun indicating right-to-left run direction.
      * @hide
@@ -136,7 +136,7 @@
     /**
      * Construct a canvas with the specified bitmap to draw into. The bitmap
      * must be mutable.
-     * 
+     *
      * <p>The initial target density of the canvas is the same as the given
      * bitmap's density.
      *
@@ -177,10 +177,10 @@
 
     /**
      * Indicates whether this Canvas uses hardware acceleration.
-     * 
+     *
      * Note that this method does not define what type of hardware acceleration
      * may or may not be used.
-     * 
+     *
      * @return True if drawing operations are hardware accelerated,
      *         false otherwise.
      */
@@ -189,7 +189,7 @@
     }
 
     /**
-     * Specify a bitmap for the canvas to draw into. All canvas state such as 
+     * Specify a bitmap for the canvas to draw into. All canvas state such as
      * layers, filters, and the save/restore stack are reset with the exception
      * of the current matrix and clip stack. Additionally, as a side-effect
      * the canvas' target density is updated to match that of the bitmap.
@@ -279,7 +279,7 @@
      * to determine the scaling factor when drawing a bitmap into it.
      *
      * @see #setDensity(int)
-     * @see Bitmap#getDensity() 
+     * @see Bitmap#getDensity()
      */
     public int getDensity() {
         return mDensity;
@@ -295,7 +295,7 @@
      * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
      *
      * @see #getDensity()
-     * @see Bitmap#setDensity(int) 
+     * @see Bitmap#setDensity(int)
      */
     public void setDensity(int density) {
         if (mBitmap != null) {
@@ -313,19 +313,19 @@
      * Returns the maximum allowed width for bitmaps drawn with this canvas.
      * Attempting to draw with a bitmap wider than this value will result
      * in an error.
-     * 
-     * @see #getMaximumBitmapHeight() 
+     *
+     * @see #getMaximumBitmapHeight()
      */
     public int getMaximumBitmapWidth() {
         return MAXMIMUM_BITMAP_SIZE;
     }
-    
+
     /**
      * Returns the maximum allowed height for bitmaps drawn with this canvas.
      * Attempting to draw with a bitmap taller than this value will result
      * in an error.
-     * 
-     * @see #getMaximumBitmapWidth() 
+     *
+     * @see #getMaximumBitmapWidth()
      */
     public int getMaximumBitmapHeight() {
         return MAXMIMUM_BITMAP_SIZE;
@@ -357,8 +357,8 @@
     /** clip against the layer's bounds */
     public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
     /** restore everything when restore() is called */
-    public static final int ALL_SAVE_FLAG = 0x1F; 
-    
+    public static final int ALL_SAVE_FLAG = 0x1F;
+
     /**
      * Saves the current matrix and clip onto a private stack. Subsequent
      * calls to translate,scale,rotate,skew,concat or clipRect,clipPath
@@ -371,7 +371,7 @@
     public int save() {
         return native_save(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
     }
-    
+
     /**
      * Based on saveFlags, can save the current matrix and clip onto a private
      * stack. Subsequent calls to translate,scale,rotate,skew,concat or
@@ -589,25 +589,25 @@
     public void concat(@Nullable Matrix matrix) {
         if (matrix != null) native_concat(mNativeCanvasWrapper, matrix.native_instance);
     }
-    
+
     /**
      * Completely replace the current matrix with the specified matrix. If the
      * matrix parameter is null, then the current matrix is reset to identity.
-     * 
+     *
      * <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)},
      * {@link #scale(float, float)}, {@link #translate(float, float)} and
      * {@link #rotate(float)} instead of this method.
      *
      * @param matrix The matrix to replace the current matrix with. If it is
      *               null, set the current matrix to identity.
-     *               
-     * @see #concat(Matrix) 
+     *
+     * @see #concat(Matrix)
      */
     public void setMatrix(@Nullable Matrix matrix) {
         native_setMatrix(mNativeCanvasWrapper,
                          matrix == null ? 0 : matrix.native_instance);
     }
-    
+
     /**
      * Return, in ctm, the current transformation matrix. This does not alter
      * the matrix in the canvas, but just returns a copy of it.
@@ -628,7 +628,7 @@
         getMatrix(m);
         return m;
     }
-    
+
     /**
      * Modify the current clip with the specified rectangle.
      *
@@ -677,7 +677,7 @@
         return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
                 Region.Op.INTERSECT.nativeInt);
     }
-    
+
     /**
      * Modify the current clip with the specified rectangle, which is
      * expressed in local coordinates.
@@ -744,7 +744,7 @@
     public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
         return native_clipPath(mNativeCanvasWrapper, path.ni(), op.nativeInt);
     }
-    
+
     /**
      * Intersect the current clip with the specified path.
      *
@@ -754,7 +754,7 @@
     public boolean clipPath(@NonNull Path path) {
         return clipPath(path, Region.Op.INTERSECT);
     }
-    
+
     /**
      * Modify the current clip with the specified region. Note that unlike
      * clipRect() and clipPath() which transform their arguments by the
@@ -789,11 +789,11 @@
     public boolean clipRegion(@NonNull Region region) {
         return clipRegion(region, Region.Op.INTERSECT);
     }
-    
+
     public @Nullable DrawFilter getDrawFilter() {
         return mDrawFilter;
     }
-    
+
     public void setDrawFilter(@Nullable DrawFilter filter) {
         long nativeFilter = 0;
         if (filter != null) {
@@ -814,7 +814,7 @@
          * Antialiased: Treat edges by rounding-out, since they may be antialiased
          */
         AA(1);
-        
+
         EdgeType(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -900,7 +900,7 @@
     public boolean getClipBounds(@Nullable Rect bounds) {
         return native_getClipBounds(mNativeCanvasWrapper, bounds);
     }
-    
+
     /**
      * Retrieve the bounds of the current clip (in local coordinates).
      *
@@ -911,7 +911,7 @@
         getClipBounds(r);
         return r;
     }
-    
+
     /**
      * Fill the entire canvas' bitmap (restricted to the current clip) with the
      * specified RGB color, using srcover porterduff mode.
@@ -968,7 +968,7 @@
     public void drawPaint(@NonNull Paint paint) {
         native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint);
     }
-    
+
     /**
      * Draw a series of points. Each point is centered at the coordinate
      * specified by pts[], and its diameter is specified by the paint's stroke
@@ -1065,7 +1065,7 @@
     public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
         drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
-    
+
 
     /**
      * Draw the specified Rect using the specified paint. The rectangle will
@@ -1091,7 +1091,15 @@
         if (oval == null) {
             throw new NullPointerException();
         }
-        native_drawOval(mNativeCanvasWrapper, oval, paint.mNativePaint);
+        drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
+    }
+
+    /**
+     * Draw the specified oval using the specified paint. The oval will be
+     * filled or framed based on the Style in the paint.
+     */
+    public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
+        native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
     }
 
     /**
@@ -1111,15 +1119,15 @@
     /**
      * <p>Draw the specified arc, which will be scaled to fit inside the
      * specified oval.</p>
-     * 
+     *
      * <p>If the start angle is negative or >= 360, the start angle is treated
      * as start angle modulo 360.</p>
-     * 
+     *
      * <p>If the sweep angle is >= 360, then the oval is drawn
      * completely. Note that this differs slightly from SkPath::arcTo, which
      * treats the sweep angle modulo 360. If the sweep angle is negative,
      * the sweep angle is treated as sweep angle modulo 360</p>
-     * 
+     *
      * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
      * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
      *
@@ -1133,10 +1141,34 @@
      */
     public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             @NonNull Paint paint) {
-        if (oval == null) {
-            throw new NullPointerException();
-        }
-        native_drawArc(mNativeCanvasWrapper, oval, startAngle, sweepAngle,
+        drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
+                paint);
+    }
+
+    /**
+     * <p>Draw the specified arc, which will be scaled to fit inside the
+     * specified oval.</p>
+     *
+     * <p>If the start angle is negative or >= 360, the start angle is treated
+     * as start angle modulo 360.</p>
+     *
+     * <p>If the sweep angle is >= 360, then the oval is drawn
+     * completely. Note that this differs slightly from SkPath::arcTo, which
+     * treats the sweep angle modulo 360. If the sweep angle is negative,
+     * the sweep angle is treated as sweep angle modulo 360</p>
+     *
+     * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
+     * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
+     *
+     * @param startAngle Starting angle (in degrees) where the arc begins
+     * @param sweepAngle Sweep angle (in degrees) measured clockwise
+     * @param useCenter If true, include the center of the oval in the arc, and
+                        close it if it is being stroked. This will draw a wedge
+     * @param paint      The paint used to draw the arc
+     */
+    public void drawArc(float left, float top, float right, float bottom, float startAngle,
+            float sweepAngle, boolean useCenter, @NonNull Paint paint) {
+        native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
                 useCenter, paint.mNativePaint);
     }
 
@@ -1197,7 +1229,7 @@
      * @param patch The ninepatch object to render
      * @param dst The destination rectangle.
      * @param paint The paint to draw the bitmap with. may be null
-     * 
+     *
      * @hide
      */
     public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
@@ -1220,7 +1252,7 @@
     /**
      * Draw the specified bitmap, with its top/left corner at (x,y), using
      * the specified paint, transformed by the current matrix.
-     * 
+     *
      * <p>Note: if the paint contains a maskfilter that generates a mask which
      * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
      * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1230,7 +1262,7 @@
      * <p>If the bitmap and canvas have different densities, this function
      * will take care of automatically scaling the bitmap to draw at the
      * same density as the canvas.
-     * 
+     *
      * @param bitmap The bitmap to be drawn
      * @param left   The position of the left side of the bitmap being drawn
      * @param top    The position of the top side of the bitmap being drawn
@@ -1246,7 +1278,7 @@
      * Draw the specified bitmap, scaling/translating automatically to fill
      * the destination rectangle. If the source rectangle is not null, it
      * specifies the subset of the bitmap to draw.
-     * 
+     *
      * <p>Note: if the paint contains a maskfilter that generates a mask which
      * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
      * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1257,7 +1289,7 @@
      * This is because the source and destination rectangle coordinate
      * spaces are in their respective densities, so must already have the
      * appropriate scaling factor applied.
-     * 
+     *
      * @param bitmap The bitmap to be drawn
      * @param src    May be null. The subset of the bitmap to be drawn
      * @param dst    The rectangle that the bitmap will be scaled/translated
@@ -1278,7 +1310,7 @@
      * Draw the specified bitmap, scaling/translating automatically to fill
      * the destination rectangle. If the source rectangle is not null, it
      * specifies the subset of the bitmap to draw.
-     * 
+     *
      * <p>Note: if the paint contains a maskfilter that generates a mask which
      * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
      * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1289,7 +1321,7 @@
      * This is because the source and destination rectangle coordinate
      * spaces are in their respective densities, so must already have the
      * appropriate scaling factor applied.
-     * 
+     *
      * @param bitmap The bitmap to be drawn
      * @param src    May be null. The subset of the bitmap to be drawn
      * @param dst    The rectangle that the bitmap will be scaled/translated
@@ -1305,7 +1337,7 @@
         native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), src, dst,
                 paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
     }
-    
+
     /**
      * Treat the specified array of colors as a bitmap, and draw it. This gives
      * the same result as first creating a bitmap from the array, and then
@@ -1394,7 +1426,7 @@
             throw new ArrayIndexOutOfBoundsException();
         }
     }
-    
+
     /**
      * Draw the bitmap through the mesh, where mesh vertices are evenly
      * distributed across the bitmap. There are meshWidth+1 vertices across, and
@@ -1446,7 +1478,7 @@
         TRIANGLES(0),
         TRIANGLE_STRIP(1),
         TRIANGLE_FAN(2);
-        
+
         VertexMode(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -1456,7 +1488,7 @@
          */
         public final int nativeInt;
     }
-    
+
     /**
      * Draw the array of vertices, interpreted as triangles (based on mode). The
      * verts array is required, and specifies the x,y pairs for each vertex. If
@@ -1485,7 +1517,7 @@
      * @param indices If not null, array of indices to reference into the
      *      vertex (texs, colors) array.
      * @param indexCount number of entries in the indices array (if not null).
-     * @param paint Specifies the shader to use if the texs array is non-null. 
+     * @param paint Specifies the shader to use if the texs array is non-null.
      */
     public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
             int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
@@ -1595,7 +1627,7 @@
      * bidi on the provided text, but renders it as a uniform right-to-left or
      * left-to-right run, as indicated by dir. Alignment of the text is as
      * determined by the Paint's TextAlign value.
-     * 
+     *
      * @param text the text to render
      * @param index the start of the text to render
      * @param count the count of chars to render
@@ -1606,13 +1638,12 @@
      *         + count.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
-     * @param dir the run direction, either {@link #DIRECTION_LTR} or
-     *         {@link #DIRECTION_RTL}.
+     * @param isRtl whether the run is in RTL direction
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
-            int contextCount, float x, float y, int dir, @NonNull Paint paint) {
+            int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1623,12 +1654,9 @@
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown dir: " + dir);
-        }
 
         native_drawTextRun(mNativeCanvasWrapper, text, index, count,
-                contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface);
+                contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1644,12 +1672,12 @@
      *            position can be used for shaping context.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
-     * @param dir the run direction, either 0 for LTR or 1 for RTL.
+     * @param isRtl whether the run is in RTL direction
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
-            int contextEnd, float x, float y, int dir, @NonNull Paint paint) {
+            int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1661,22 +1689,20 @@
             throw new IndexOutOfBoundsException();
         }
 
-        int flags = dir == 0 ? 0 : 1;
-
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+                    contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
-                    contextStart, contextEnd, x, y, flags, paint);
+                    contextStart, contextEnd, x, y, isRtl, paint);
         } else {
             int contextLen = contextEnd - contextStart;
             int len = end - start;
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
-                    0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+                    0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1684,7 +1710,7 @@
     /**
      * Draw the text in the array, with each character's origin specified by
      * the pos array.
-     * 
+     *
      * This method does not support glyph composition and decomposition and
      * should therefore not be used to render complex scripts.
      *
@@ -1708,7 +1734,7 @@
     /**
      * Draw the text in the array, with each character's origin specified by
      * the pos array.
-     * 
+     *
      * This method does not support glyph composition and decomposition and
      * should therefore not be used to render complex scripts.
      *
@@ -1776,7 +1802,7 @@
      * <p>
      * <strong>Note:</strong> This forces the picture to internally call
      * {@link Picture#endRecording} in order to prepare for playback.
-     * 
+     *
      * @param picture  The picture to be drawn
      */
     public void drawPicture(@NonNull Picture picture) {
@@ -1785,7 +1811,7 @@
         picture.draw(this);
         restoreToCount(restoreCount);
     }
-    
+
     /**
      * Draw the picture, stretched to fit into the dst rectangle.
      */
@@ -1798,7 +1824,7 @@
         drawPicture(picture);
         restore();
     }
-    
+
     /**
      * Draw the picture, stretched to fit into the dst rectangle.
      */
@@ -1914,14 +1940,14 @@
                                                float top, float right,
                                                float bottom,
                                                long nativePaint);
-    private static native void native_drawOval(long nativeCanvas, RectF oval,
-                                               long nativePaint);
+    private static native void native_drawOval(long nativeCanvas, float left, float top,
+                                               float right, float bottom, long nativePaint);
     private static native void native_drawCircle(long nativeCanvas, float cx,
                                                  float cy, float radius,
                                                  long nativePaint);
-    private static native void native_drawArc(long nativeCanvas, RectF oval,
-                                              float startAngle, float sweep,
-                                              boolean useCenter,
+    private static native void native_drawArc(long nativeCanvas, float left, float top,
+                                              float right, float bottom,
+                                              float startAngle, float sweep, boolean useCenter,
                                               long nativePaint);
     private static native void native_drawRoundRect(long nativeCanvas,
             float left, float top, float right, float bottom,
@@ -1977,11 +2003,11 @@
 
     private static native void native_drawTextRun(long nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, long nativePaint, long nativeTypeface);
+            float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
 
     private static native void native_drawTextRun(long nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int flags, long nativePaint, long nativeTypeface);
+            float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
 
     private static native void native_drawPosText(long nativeCanvas,
                                                   char[] text, int index,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 4268a24..17ce026 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -56,7 +56,7 @@
      * @hide
      */
     public  int         mBidiFlags = BIDI_DEFAULT_LTR;
-    
+
     static final Style[] sStyleArray = {
         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
     };
@@ -202,14 +202,14 @@
 
     /**
      * Bidi flag to set LTR paragraph direction.
-     * 
+     *
      * @hide
      */
     public static final int BIDI_LTR = 0x0;
 
     /**
      * Bidi flag to set RTL paragraph direction.
-     * 
+     *
      * @hide
      */
     public static final int BIDI_RTL = 0x1;
@@ -217,7 +217,7 @@
     /**
      * Bidi flag to detect paragraph direction via heuristics, defaulting to
      * LTR.
-     * 
+     *
      * @hide
      */
     public static final int BIDI_DEFAULT_LTR = 0x2;
@@ -225,21 +225,21 @@
     /**
      * Bidi flag to detect paragraph direction via heuristics, defaulting to
      * RTL.
-     * 
+     *
      * @hide
      */
     public static final int BIDI_DEFAULT_RTL = 0x3;
 
     /**
      * Bidi flag to override direction to all LTR (ignore bidi).
-     * 
+     *
      * @hide
      */
     public static final int BIDI_FORCE_LTR = 0x4;
 
     /**
      * Bidi flag to override direction to all RTL (ignore bidi).
-     * 
+     *
      * @hide
      */
     public static final int BIDI_FORCE_RTL = 0x5;
@@ -331,7 +331,7 @@
          * either FILL or STROKE.
          */
         FILL_AND_STROKE (2);
-        
+
         Style(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -357,7 +357,7 @@
          * of the path.
          */
         SQUARE  (2);
-        
+
         private Cap(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -381,7 +381,7 @@
          * The outer edges of a join meet with a straight line
          */
         BEVEL   (2);
-        
+
         private Join(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -405,7 +405,7 @@
          * The text is drawn to the left of the x,y origin
          */
         RIGHT   (2);
-        
+
         private Align(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -418,7 +418,7 @@
     public Paint() {
         this(0);
     }
-    
+
     /**
      * Create a new paint with the specified flags. Use setFlags() to change
      * these after the paint is created.
@@ -475,7 +475,7 @@
         setTextLocale(Locale.getDefault());
         setElegantTextHeight(false);
     }
-    
+
     /**
      * Copy the fields from src into this paint. This is equivalent to calling
      * get() on all of the src fields, and calling the corresponding set()
@@ -529,7 +529,7 @@
 
     /**
      * Return the bidi flags on the paint.
-     * 
+     *
      * @return the bidi flags on the paint
      * @hide
      */
@@ -552,7 +552,7 @@
 
     /**
      * Return the paint's flags. Use the Flag enum to test flag values.
-     * 
+     *
      * @return the paint's flags (see enums ending in _Flag for bit masks)
      */
     public native int getFlags();
@@ -587,7 +587,7 @@
     public final boolean isAntiAlias() {
         return (getFlags() & ANTI_ALIAS_FLAG) != 0;
     }
-    
+
     /**
      * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
      * AntiAliasing smooths out the edges of what is being drawn, but is has
@@ -597,7 +597,7 @@
      * @param aa true to set the antialias bit in the flags, false to clear it
      */
     public native void setAntiAlias(boolean aa);
-    
+
     /**
      * Helper for getFlags(), returning true if DITHER_FLAG bit is set
      * Dithering affects how colors that are higher precision than the device
@@ -611,7 +611,7 @@
     public final boolean isDither() {
         return (getFlags() & DITHER_FLAG) != 0;
     }
-    
+
     /**
      * Helper for setFlags(), setting or clearing the DITHER_FLAG bit
      * Dithering affects how colors that are higher precision than the device
@@ -623,7 +623,7 @@
      * @param dither true to set the dithering bit in flags, false to clear it
      */
     public native void setDither(boolean dither);
-    
+
     /**
      * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
      *
@@ -649,7 +649,7 @@
     public final boolean isSubpixelText() {
         return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
     }
-    
+
     /**
      * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
      *
@@ -657,7 +657,7 @@
      *                     flags, false to clear it.
      */
     public native void setSubpixelText(boolean subpixelText);
-    
+
     /**
      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
      *
@@ -708,7 +708,7 @@
      *                     flags, false to clear it.
      */
     public native void setFakeBoldText(boolean fakeBoldText);
-    
+
     /**
      * Whether or not the bitmap filter is activated.
      * Filtering affects the sampling of bitmaps when they are transformed.
@@ -720,13 +720,13 @@
     public final boolean isFilterBitmap() {
         return (getFlags() & FILTER_BITMAP_FLAG) != 0;
     }
-    
+
     /**
      * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
      * Filtering affects the sampling of bitmaps when they are transformed.
      * Filtering does not affect how the colors in the bitmap are converted into
      * device pixels. That is dependent on dithering and xfermodes.
-     * 
+     *
      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
      *               flags, false to clear it.
      */
@@ -773,7 +773,7 @@
      * @param color The new color (including alpha) to set in the paint.
      */
     public native void setColor(int color);
-    
+
     /**
      * Helper to getColor() that just returns the color's alpha value. This is
      * the same as calling getColor() >>> 24. It always returns a value between
@@ -1285,7 +1285,7 @@
      */
     public static class FontMetrics {
         /**
-         * The maximum distance above the baseline for the tallest glyph in 
+         * The maximum distance above the baseline for the tallest glyph in
          * the font at a given text size.
          */
         public float   top;
@@ -1298,7 +1298,7 @@
          */
         public float   descent;
         /**
-         * The maximum distance below the baseline for the lowest glyph in 
+         * The maximum distance below the baseline for the lowest glyph in
          * the font at a given text size.
          */
         public float   bottom;
@@ -1307,7 +1307,7 @@
          */
         public float   leading;
     }
-    
+
     /**
      * Return the font's recommended interline spacing, given the Paint's
      * settings for typeface, textSize, etc. If metrics is not null, return the
@@ -1318,7 +1318,7 @@
      * @return the font's recommended interline spacing.
      */
     public native float getFontMetrics(FontMetrics metrics);
-    
+
     /**
      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
      * with it, returning the object.
@@ -1328,7 +1328,7 @@
         getFontMetrics(fm);
         return fm;
     }
-    
+
     /**
      * Convenience method for callers that want to have FontMetrics values as
      * integers.
@@ -1339,7 +1339,7 @@
         public int   descent;
         public int   bottom;
         public int   leading;
-        
+
         @Override public String toString() {
             return "FontMetricsInt: top=" + top + " ascent=" + ascent +
                     " descent=" + descent + " bottom=" + bottom +
@@ -1364,7 +1364,7 @@
         getFontMetricsInt(fm);
         return fm;
     }
-    
+
     /**
      * Return the recommend line spacing based on the current typeface and
      * text size.
@@ -1407,7 +1407,7 @@
     }
 
     private native float native_measureText(char[] text, int index, int count, int bidiFlags);
-    
+
     /**
      * Return the width of the text.
      *
@@ -1439,7 +1439,7 @@
     }
 
     private native float native_measureText(String text, int start, int end, int bidiFlags);
-    
+
     /**
      * Return the width of the text.
      *
@@ -1466,7 +1466,7 @@
     }
 
     private native float native_measureText(String text, int bidiFlags);
-    
+
     /**
      * Return the width of the text.
      *
@@ -1503,7 +1503,7 @@
         TemporaryBuffer.recycle(buf);
         return result;
     }
-    
+
     /**
      * Measure the text, stopping early if the measured width exceeds maxWidth.
      * Return the number of chars that were measured, and if measuredWidth is
@@ -1532,20 +1532,22 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
+            return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
+                    mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
-        setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
-                measuredWidth);
+        setTextSize(oldSize * mCompatScaling);
+        int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
+                maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
         return res;
     }
 
-    private native int native_breakText(char[] text, int index, int count,
-                                        float maxWidth, int bidiFlags, float[] measuredWidth);
+    private static native int native_breakText(long native_object, long native_typeface,
+                                               char[] text, int index, int count,
+                                               float maxWidth, int bidiFlags, float[] measuredWidth);
 
     /**
      * Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1622,19 +1624,21 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
+            return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+                    maxWidth, mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
-                measuredWidth);
+        int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+                maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
         return res;
     }
 
-    private native int native_breakText(String text, boolean measureForwards,
+    private static native int native_breakText(long native_object, long native_typeface,
+                                        String text, boolean measureForwards,
                                         float maxWidth, int bidiFlags, float[] measuredWidth);
 
     /**
@@ -1738,7 +1742,7 @@
         if (end - start > widths.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        
+
         if (text.length() == 0 || start == end) {
             return 0;
         }
@@ -1755,7 +1759,7 @@
         }
         return res;
     }
-    
+
     /**
      * Return the advance widths for the characters in the string.
      *
@@ -1816,15 +1820,12 @@
      * @hide
      */
     public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, int flags, float[] advances,
+            int contextIndex, int contextCount, boolean isRtl, float[] advances,
             int advancesIndex) {
 
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
-        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown flags value: " + flags);
-        }
         if ((index | count | contextIndex | contextCount | advancesIndex
                 | (index - contextIndex) | (contextCount - count)
                 | ((contextIndex + contextCount) - (index + count))
@@ -1839,13 +1840,13 @@
         }
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
-                    contextIndex, contextCount, flags, advances, advancesIndex);
+                    contextIndex, contextCount, isRtl, advances, advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
-                contextIndex, contextCount, flags, advances, advancesIndex);
+                contextIndex, contextCount, isRtl, advances, advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1864,7 +1865,7 @@
      * @hide
      */
     public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, int flags, float[] advances,
+            int contextStart, int contextEnd, boolean isRtl, float[] advances,
             int advancesIndex) {
 
         if (text == null) {
@@ -1880,16 +1881,16 @@
 
         if (text instanceof String) {
             return getTextRunAdvances((String) text, start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex);
+                    contextStart, contextEnd, isRtl, advances, advancesIndex);
         }
         if (text instanceof SpannedString ||
             text instanceof SpannableString) {
             return getTextRunAdvances(text.toString(), start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex);
+                    contextStart, contextEnd, isRtl, advances, advancesIndex);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex, this);
+                    contextStart, contextEnd, isRtl, advances, advancesIndex, this);
         }
         if (text.length() == 0 || end == start) {
             return 0f;
@@ -1900,7 +1901,7 @@
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
         float result = getTextRunAdvances(buf, start - contextStart, len,
-                0, contextLen, flags, advances, advancesIndex);
+                0, contextLen, isRtl, advances, advancesIndex);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -1937,8 +1938,7 @@
      * must be <= start
      * @param contextEnd the index past the last character to use for shaping context,
      * must be >= end
-     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
-     * or {@link #DIRECTION_RTL}
+     * @param isRtl whether the run is in RTL direction
      * @param advances array to receive the advances, must have room for all advances,
      * can be null if only total advance is needed
      * @param advancesIndex the position in advances at which to put the
@@ -1948,14 +1948,11 @@
      * @hide
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, int flags, float[] advances, int advancesIndex) {
+            int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
 
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
-        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
-            throw new IllegalArgumentException("unknown flags value: " + flags);
-        }
         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
                 | (start - contextStart) | (contextEnd - end)
                 | (text.length() - contextEnd)
@@ -1970,13 +1967,13 @@
 
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
-                    contextStart, contextEnd, flags, advances, advancesIndex);
+                    contextStart, contextEnd, isRtl, advances, advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
-                contextStart, contextEnd, flags, advances, advancesIndex);
+                contextStart, contextEnd, isRtl, advances, advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -2005,7 +2002,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextLength the length of the context
-     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2014,7 +2011,7 @@
      * @hide
      */
     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
-            int flags, int offset, int cursorOpt) {
+            int dir, int offset, int cursorOpt) {
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -2024,7 +2021,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextLength, flags, offset, cursorOpt);
+                contextStart, contextLength, dir, offset, cursorOpt);
     }
 
     /**
@@ -2045,7 +2042,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
-     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2054,22 +2051,22 @@
      * @hide
      */
     public int getTextRunCursor(CharSequence text, int contextStart,
-           int contextEnd, int flags, int offset, int cursorOpt) {
+           int contextEnd, int dir, int offset, int cursorOpt) {
 
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             return getTextRunCursor(text.toString(), contextStart, contextEnd,
-                    flags, offset, cursorOpt);
+                    dir, offset, cursorOpt);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunCursor(
-                    contextStart, contextEnd, flags, offset, cursorOpt, this);
+                    contextStart, contextEnd, dir, offset, cursorOpt, this);
         }
 
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
+        int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -2092,7 +2089,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
-     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2101,7 +2098,7 @@
      * @hide
      */
     public int getTextRunCursor(String text, int contextStart, int contextEnd,
-            int flags, int offset, int cursorOpt) {
+            int dir, int offset, int cursorOpt) {
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
                 | (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2110,7 +2107,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextEnd, flags, offset, cursorOpt);
+                contextStart, contextEnd, dir, offset, cursorOpt);
     }
 
     /**
@@ -2156,7 +2153,7 @@
         native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
                 path.ni());
     }
-    
+
     /**
      * Return in bounds (allocated by the caller) the smallest rectangle that
      * encloses all of the characters, with an implied origin at (0,0).
@@ -2176,7 +2173,7 @@
         }
         nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
     }
-    
+
     /**
      * Return in bounds (allocated by the caller) the smallest rectangle that
      * encloses all of the characters, with an implied origin at (0,0).
@@ -2197,7 +2194,7 @@
         nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
             bounds);
     }
-    
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -2252,15 +2249,15 @@
 
     private static native float native_getTextRunAdvances(long native_object, long native_typeface,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            int flags, float[] advances, int advancesIndex);
+            boolean isRtl, float[] advances, int advancesIndex);
     private static native float native_getTextRunAdvances(long native_object, long native_typeface,
             String text, int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex);
+            boolean isRtl, float[] advances, int advancesIndex);
 
     private native int native_getTextRunCursor(long native_object, char[] text,
-            int contextStart, int contextLength, int flags, int offset, int cursorOpt);
+            int contextStart, int contextLength, int dir, int offset, int cursorOpt);
     private native int native_getTextRunCursor(long native_object, String text,
-            int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
+            int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
 
     private static native void native_getTextPath(long native_object, long native_typeface,
             int bidiFlags, char[] text, int index, int count, float x, float y, long path);
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c600f47..c40a66d 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -62,7 +62,7 @@
         }
         mNativePath = init2(valNative);
     }
-    
+
     /**
      * Clear any lines and curves from the path, making it empty.
      * This does NOT change the fill-type setting.
@@ -205,7 +205,7 @@
          * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
          */
         INVERSE_EVEN_ODD(3);
-        
+
         FillType(int ni) {
             nativeInt = ni;
         }
@@ -425,7 +425,7 @@
      * the path is different from the path's current last point, then an
      * automatic lineTo() is added to connect the current contour to the
      * start of the arc. However, if the path is empty, then we call moveTo()
-     * with the first point of the arc. The sweep angle is tread mod 360.
+     * with the first point of the arc.
      *
      * @param oval        The bounds of oval defining shape and size of the arc
      * @param startAngle  Starting angle (in degrees) where the arc begins
@@ -435,10 +435,9 @@
      */
     public void arcTo(RectF oval, float startAngle, float sweepAngle,
                       boolean forceMoveTo) {
-        isSimplePath = false;
-        native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
+        arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
     }
-    
+
     /**
      * Append the specified arc to the path as a new contour. If the start of
      * the path is different from the path's current last point, then an
@@ -451,10 +450,27 @@
      * @param sweepAngle  Sweep angle (in degrees) measured clockwise
      */
     public void arcTo(RectF oval, float startAngle, float sweepAngle) {
-        isSimplePath = false;
-        native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
+        arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
     }
-    
+
+    /**
+     * Append the specified arc to the path as a new contour. If the start of
+     * the path is different from the path's current last point, then an
+     * automatic lineTo() is added to connect the current contour to the
+     * start of the arc. However, if the path is empty, then we call moveTo()
+     * with the first point of the arc.
+     *
+     * @param startAngle  Starting angle (in degrees) where the arc begins
+     * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
+     *                    mod 360.
+     * @param forceMoveTo If true, always begin a new contour with the arc
+     */
+    public void arcTo(float left, float top, float right, float bottom, float startAngle,
+            float sweepAngle, boolean forceMoveTo) {
+        isSimplePath = false;
+        native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
+    }
+
     /**
      * Close the current contour. If the current point is not equal to the
      * first point of the contour, a line segment is automatically added.
@@ -473,13 +489,13 @@
         CW  (1),    // must match enum in SkPath.h
         /** counter-clockwise */
         CCW (2);    // must match enum in SkPath.h
-        
+
         Direction(int ni) {
             nativeInt = ni;
         }
         final int nativeInt;
     }
-    
+
     private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
         if (mLastDirection == null) {
             mLastDirection = dir;
@@ -557,11 +573,19 @@
      * @param sweepAngle Sweep angle (in degrees) measured clockwise
      */
     public void addArc(RectF oval, float startAngle, float sweepAngle) {
-        if (oval == null) {
-            throw new NullPointerException("need oval parameter");
-        }
+        addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
+    }
+
+    /**
+     * Add the specified arc to the path as a new contour.
+     *
+     * @param startAngle Starting angle (in degrees) where the arc begins
+     * @param sweepAngle Sweep angle (in degrees) measured clockwise
+     */
+    public void addArc(float left, float top, float right, float bottom, float startAngle,
+            float sweepAngle) {
         isSimplePath = false;
-        native_addArc(mNativePath, oval, startAngle, sweepAngle);
+        native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
     }
 
     /**
@@ -573,13 +597,22 @@
      * @param dir  The direction to wind the round-rectangle's contour
      */
     public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
-        if (rect == null) {
-            throw new NullPointerException("need rect parameter");
-        }
-        isSimplePath = false;
-        native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
+        addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
     }
-    
+
+    /**
+     * Add a closed round-rectangle contour to the path
+     *
+     * @param rx   The x-radius of the rounded corners on the round-rectangle
+     * @param ry   The y-radius of the rounded corners on the round-rectangle
+     * @param dir  The direction to wind the round-rectangle's contour
+     */
+    public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+            Direction dir) {
+        isSimplePath = false;
+        native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
+    }
+
     /**
      * Add a closed round-rectangle contour to the path. Each corner receives
      * two radius values [X, Y]. The corners are ordered top-left, top-right,
@@ -593,13 +626,26 @@
         if (rect == null) {
             throw new NullPointerException("need rect parameter");
         }
+        addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
+    }
+
+    /**
+     * Add a closed round-rectangle contour to the path. Each corner receives
+     * two radius values [X, Y]. The corners are ordered top-left, top-right,
+     * bottom-right, bottom-left
+     *
+     * @param radii Array of 8 values, 4 pairs of [X,Y] radii
+     * @param dir  The direction to wind the round-rectangle's contour
+     */
+    public void addRoundRect(float left, float top, float right, float bottom, float[] radii,
+            Direction dir) {
         if (radii.length < 8) {
             throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
         }
         isSimplePath = false;
-        native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
+        native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
     }
-    
+
     /**
      * Add a copy of src to the path, offset by (dx,dy)
      *
@@ -755,19 +801,24 @@
                                         float x2, float y2, float x3, float y3);
     private static native void native_rCubicTo(long nPath, float x1, float y1,
                                         float x2, float y2, float x3, float y3);
-    private static native void native_arcTo(long nPath, RectF oval,
-                    float startAngle, float sweepAngle, boolean forceMoveTo);
+    private static native void native_arcTo(long nPath, float left, float top,
+                                            float right, float bottom, float startAngle,
+                                            float sweepAngle, boolean forceMoveTo);
     private static native void native_close(long nPath);
     private static native void native_addRect(long nPath, float left, float top,
                                             float right, float bottom, int dir);
     private static native void native_addOval(long nPath, float left, float top,
             float right, float bottom, int dir);
     private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
-    private static native void native_addArc(long nPath, RectF oval,
-                                            float startAngle, float sweepAngle);
-    private static native void native_addRoundRect(long nPath, RectF rect,
+    private static native void native_addArc(long nPath, float left, float top,
+                                             float right, float bottom,
+                                             float startAngle, float sweepAngle);
+    private static native void native_addRoundRect(long nPath, float left, float top,
+                                                   float right, float bottom,
                                                    float rx, float ry, int dir);
-    private static native void native_addRoundRect(long nPath, RectF r, float[] radii, int dir);
+    private static native void native_addRoundRect(long nPath, float left, float top,
+                                                   float right, float bottom,
+                                                   float[] radii, int dir);
     private static native void native_addPath(long nPath, long src, float dx, float dy);
     private static native void native_addPath(long nPath, long src);
     private static native void native_addPath(long nPath, long src, long matrix);
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index de458af..a021165 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -53,7 +53,7 @@
     public Picture(Picture src) {
         this(nativeConstructor(src != null ? src.mNativePicture : 0), false);
     }
-    
+
     /**
      * To record a picture, call beginRecording() and then draw into the Canvas
      * that is returned. Nothing we appear on screen, but all of the draw
@@ -67,7 +67,7 @@
         mRecordingCanvas = new RecordingCanvas(this, ni);
         return mRecordingCanvas;
     }
-    
+
     /**
      * Call endRecording when the picture is built. After this call, the picture
      * may be drawn, but the canvas that was returned by beginRecording must not
@@ -92,16 +92,19 @@
      * does not reflect (per se) the content of the picture.
      */
     public native int getHeight();
-    
+
     /**
-     * Draw this picture on the canvas. The picture may have the side effect
-     * of changing the matrix and clip of the canvas.
-     * 
+     * Draw this picture on the canvas.
+     * <p>
+     * Prior to {@link android.os.Build.VERSION_CODES#L}, this call could
+     * have the side effect of changing the matrix and clip of the canvas
+     * if this picture had imbalanced saves/restores.
+     *
      * <p>
      * <strong>Note:</strong> This forces the picture to internally call
      * {@link Picture#endRecording()} in order to prepare for playback.
      *
-     * @param canvas  The picture is drawn to this canvas 
+     * @param canvas  The picture is drawn to this canvas
      */
     public void draw(Canvas canvas) {
         if (mRecordingCanvas != null) {
@@ -119,7 +122,7 @@
      * <p>
      * <strong>Note:</strong> a picture created from an input stream cannot be
      * replayed on a hardware accelerated canvas.
-     * 
+     *
      * @see #writeToStream(java.io.OutputStream)
      * @deprecated The recommended alternative is to not use writeToStream and
      * instead draw the picture into a Bitmap from which you can persist it as
@@ -167,7 +170,7 @@
     final long ni() {
         return mNativePicture;
     }
-    
+
     private Picture(long nativePicture, boolean fromStream) {
         if (nativePicture == 0) {
             throw new RuntimeException();
@@ -187,7 +190,7 @@
     private static native boolean nativeWriteToStream(long nativePicture,
                                            OutputStream stream, byte[] storage);
     private static native void nativeDestructor(long nativePicture);
-    
+
     private static class RecordingCanvas extends Canvas {
         private final Picture mPicture;
 
@@ -195,7 +198,7 @@
             super(nativeCanvas);
             mPicture = pict;
         }
-        
+
         @Override
         public void setBitmap(Bitmap bitmap) {
             throw new RuntimeException(
diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java
index 9dc62c3..4edfad4 100644
--- a/graphics/java/android/graphics/drawable/Animatable.java
+++ b/graphics/java/android/graphics/drawable/Animatable.java
@@ -32,7 +32,7 @@
 
     /**
      * Indicates whether the animation is running.
-     * 
+     *
      * @return True if the animation is running, false otherwise.
      */
     boolean isRunning();
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index e8024f7..0fd4423 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -19,6 +19,8 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.ColorFilter;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
@@ -88,6 +90,7 @@
         canvas.restoreToCount(saveCount);
     }
 
+    @Override
     public void start() {
         if (!mRunning) {
             mRunning = true;
@@ -95,11 +98,13 @@
         }
     }
 
+    @Override
     public void stop() {
         mRunning = false;
         unscheduleSelf(this);
     }
 
+    @Override
     public boolean isRunning() {
         return mRunning;
     }
@@ -108,10 +113,11 @@
         unscheduleSelf(this);
         scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
     }
-    
+
+    @Override
     public void run() {
         // TODO: This should be computed in draw(Canvas), based on the amount
-        // of time since the last frame drawn 
+        // of time since the last frame drawn
         mCurrentDegrees += mIncrement;
         if (mCurrentDegrees > (360.0f - mIncrement)) {
             mCurrentDegrees = 0.0f;
@@ -119,7 +125,7 @@
         invalidateSelf();
         nextFrame();
     }
-    
+
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
         mState.mDrawable.setVisible(visible, restart);
@@ -133,8 +139,8 @@
             unscheduleSelf(this);
         }
         return changed;
-    }    
-    
+    }
+
     /**
      * Returns the drawable rotated by this RotateDrawable.
      */
@@ -148,7 +154,7 @@
                 | mState.mChangingConfigurations
                 | mState.mDrawable.getChangingConfigurations();
     }
-    
+
     @Override
     public void setAlpha(int alpha) {
         mState.mDrawable.setAlpha(alpha);
@@ -165,10 +171,16 @@
     }
 
     @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        mState.mDrawable.setTint(tint, tintMode);
+    }
+
+    @Override
     public int getOpacity() {
         return mState.mDrawable.getOpacity();
     }
 
+    @Override
     public void invalidateDrawable(Drawable who) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -176,6 +188,7 @@
         }
     }
 
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -183,6 +196,7 @@
         }
     }
 
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -194,7 +208,7 @@
     public boolean getPadding(Rect padding) {
         return mState.mDrawable.getPadding(padding);
     }
-    
+
     @Override
     public boolean isStateful() {
         return mState.mDrawable.isStateful();
@@ -206,6 +220,16 @@
     }
 
     @Override
+    protected boolean onLevelChange(int level) {
+        return mState.mDrawable.setLevel(level);
+    }
+
+    @Override
+    protected boolean onStateChange(int[] state) {
+        return mState.mDrawable.setState(state);
+    }
+
+    @Override
     public int getIntrinsicWidth() {
         return mState.mDrawable.getIntrinsicWidth();
     }
@@ -231,11 +255,11 @@
         final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable);
 
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
-        
+
         TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
         final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
         final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-        
+
         tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
         final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
         final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
@@ -250,7 +274,7 @@
         }
 
         a.recycle();
-        
+
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
@@ -306,7 +330,7 @@
         Drawable mDrawable;
 
         int mChangingConfigurations;
-        
+
         boolean mPivotXRel;
         float mPivotX;
         boolean mPivotYRel;
@@ -315,7 +339,7 @@
         int mFramesCount;
 
         private boolean mCanConstantState;
-        private boolean mCheckedConstantState;        
+        private boolean mCheckedConstantState;
 
         public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
                 Resources res) {
@@ -341,12 +365,12 @@
         public Drawable newDrawable() {
             return new AnimatedRotateDrawable(this, null);
         }
-        
+
         @Override
         public Drawable newDrawable(Resources res) {
             return new AnimatedRotateDrawable(this, res);
         }
-        
+
         @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index a5a074c..e1dec9d 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -537,4 +537,3 @@
         }
     }
 }
-
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
new file mode 100644
index 0000000..968c0ec
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -0,0 +1,250 @@
+/*
+ * 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.AnimatorInflater;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * AnimatedVectorDrawable can use ObjectAnimator and AnimatorSet to animate
+ * the property of the VectorDrawable.
+ *
+ * @hide
+ */
+public class AnimatedVectorDrawable extends Drawable implements Animatable {
+    private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
+
+    private static final String ANIMATED_VECTOR = "animated-vector";
+    private static final String TARGET = "target";
+
+    private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+
+    private final AnimatedVectorDrawableState mAnimatedVectorState;
+
+
+    public AnimatedVectorDrawable() {
+        mAnimatedVectorState = new AnimatedVectorDrawableState(
+                new AnimatedVectorDrawableState(null));
+    }
+
+    private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
+            Theme theme) {
+        // TODO: Correctly handle the constant state for AVD.
+        mAnimatedVectorState = new AnimatedVectorDrawableState(state);
+        if (theme != null && canApplyTheme()) {
+            applyTheme(theme);
+        }
+    }
+
+    @Override
+    public ConstantState getConstantState() {
+        return null;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        mAnimatedVectorState.mVectorDrawable.draw(canvas);
+        if (isRunning()) {
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        mAnimatedVectorState.mVectorDrawable.setBounds(bounds);
+    }
+
+    @Override
+    public int getAlpha() {
+        return mAnimatedVectorState.mVectorDrawable.getAlpha();
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mAnimatedVectorState.mVectorDrawable.setAlpha(alpha);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public int getOpacity() {
+        return mAnimatedVectorState.mVectorDrawable.getOpacity();
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth();
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight();
+    }
+
+    @Override
+    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+
+        int eventType = parser.getEventType();
+        while (eventType != XmlPullParser.END_DOCUMENT) {
+            if (eventType == XmlPullParser.START_TAG) {
+                final String tagName = parser.getName();
+                if (ANIMATED_VECTOR.equals(tagName)) {
+                    final TypedArray a = obtainAttributes(res, theme, attrs,
+                            R.styleable.AnimatedVectorDrawable);
+                    int drawableRes = a.getResourceId(
+                            R.styleable.AnimatedVectorDrawable_drawable, 0);
+                    if (drawableRes != 0) {
+                        mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
+                                drawableRes);
+                    }
+                    a.recycle();
+                } else if (TARGET.equals(tagName)) {
+                    final TypedArray a = obtainAttributes(res, theme, attrs,
+                            R.styleable.AnimatedVectorDrawableTarget);
+                    final String target = a.getString(
+                            R.styleable.AnimatedVectorDrawableTarget_name);
+
+                    int id = a.getResourceId(
+                            R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+                    if (id != 0) {
+                        Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id);
+                        setupAnimatorsForTarget(target, objectAnimator);
+                    }
+                    a.recycle();
+                }
+            }
+
+            eventType = parser.next();
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        return super.canApplyTheme() || mAnimatedVectorState != null
+                && mAnimatedVectorState.canApplyTheme();
+    }
+
+    @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final VectorDrawable vectorDrawable = mAnimatedVectorState.mVectorDrawable;
+        if (vectorDrawable != null && vectorDrawable.canApplyTheme()) {
+            vectorDrawable.applyTheme(t);
+        }
+    }
+
+    private static class AnimatedVectorDrawableState extends ConstantState {
+        int mChangingConfigurations;
+        VectorDrawable mVectorDrawable;
+        ArrayList<Animator> mAnimators;
+
+        public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
+            if (copy != null) {
+                mChangingConfigurations = copy.mChangingConfigurations;
+                // TODO: Make sure the constant state are handled correctly.
+                mVectorDrawable = new VectorDrawable();
+                mAnimators = new ArrayList<Animator>();
+            }
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimatedVectorDrawable(this, null, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimatedVectorDrawable(this, res, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res, Theme theme) {
+            return new AnimatedVectorDrawable(this, res, theme);
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConfigurations;
+        }
+    }
+
+    private void setupAnimatorsForTarget(String name, Animator animator) {
+        Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
+        animator.setTarget(target);
+        mAnimatedVectorState.mAnimators.add(animator);
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.v(LOGTAG, "add animator  for target " + name + " " + animator);
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+        final int size = animators.size();
+        for (int i = 0; i < size; i++) {
+            final Animator animator = animators.get(i);
+            if (animator.isRunning()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void start() {
+        final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+        final int size = animators.size();
+        for (int i = 0; i < size; i++) {
+            final Animator animator = animators.get(i);
+            if (animator.isPaused()) {
+                animator.resume();
+            } else if (!animator.isRunning()) {
+                animator.start();
+            }
+        }
+        invalidateSelf();
+    }
+
+    @Override
+    public void stop() {
+        final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+        final int size = animators.size();
+        for (int i = 0; i < size; i++) {
+            final Animator animator = animators.get(i);
+            animator.pause();
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 16548d0..0740761 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -28,7 +28,6 @@
 import android.util.AttributeSet;
 
 /**
- * 
  * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
  * which can be used as a View object's background.
  * <p>
@@ -91,10 +90,10 @@
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        boolean changed = super.setVisible(visible, restart);
+        final boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (changed || restart) {
-                setFrame(0, true, restart || mCurFrame >= 0);
+                setFrame(0, true, mAnimating);
             }
         } else {
             unscheduleSelf(this);
@@ -114,6 +113,7 @@
      * @see #isRunning()
      * @see #stop()
      */
+    @Override
     public void start() {
         if (!isRunning()) {
             run();
@@ -127,6 +127,7 @@
      * @see #isRunning()
      * @see #start()
      */
+    @Override
     public void stop() {
         if (isRunning()) {
             unscheduleSelf(this);
@@ -138,6 +139,7 @@
      *
      * @return true if the animation is running, false otherwise
      */
+    @Override
     public boolean isRunning() {
         return mAnimating;
     }
@@ -148,6 +150,7 @@
      *
      * @see #start()
      */
+    @Override
     public void run() {
         nextFrame(false);
     }
@@ -165,41 +168,41 @@
     public int getNumberOfFrames() {
         return mAnimationState.getChildCount();
     }
-    
+
     /**
      * @return The Drawable at the specified frame index
      */
     public Drawable getFrame(int index) {
         return mAnimationState.getChild(index);
     }
-    
+
     /**
-     * @return The duration in milliseconds of the frame at the 
+     * @return The duration in milliseconds of the frame at the
      * specified index
      */
     public int getDuration(int i) {
         return mAnimationState.mDurations[i];
     }
-    
+
     /**
      * @return True of the animation will play once, false otherwise
      */
     public boolean isOneShot() {
         return mAnimationState.mOneShot;
     }
-    
+
     /**
      * Sets whether the animation should play once or repeat.
-     * 
+     *
      * @param oneShot Pass true if the animation should only play once
      */
     public void setOneShot(boolean oneShot) {
         mAnimationState.mOneShot = oneShot;
     }
-    
+
     /**
      * Add a frame to the animation
-     * 
+     *
      * @param frame The frame to add
      * @param duration How long in milliseconds the frame should appear
      */
@@ -209,7 +212,7 @@
             setFrame(0, true, false);
         }
     }
-    
+
     private void nextFrame(boolean unschedule) {
         int next = mCurFrame+1;
         final int N = mAnimationState.getChildCount();
@@ -239,21 +242,21 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        
+
         TypedArray a = r.obtainAttributes(attrs,
                 com.android.internal.R.styleable.AnimationDrawable);
 
         super.inflateWithAttributes(r, parser, a,
                 com.android.internal.R.styleable.AnimationDrawable_visible);
-        
+
         mAnimationState.setVariablePadding(a.getBoolean(
                 com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
-            
+
         mAnimationState.mOneShot = a.getBoolean(
                 com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
-        
+
         a.recycle();
-        
+
         int type;
 
         final int innerDepth = parser.getDepth()+1;
@@ -267,7 +270,7 @@
             if (depth > innerDepth || !parser.getName().equals("item")) {
                 continue;
             }
-            
+
             a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem);
             int duration = a.getInt(
                     com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
@@ -278,9 +281,9 @@
             }
             int drawableRes = a.getResourceId(
                     com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
-            
+
             a.recycle();
-            
+
             Drawable dr;
             if (drawableRes != 0) {
                 dr = r.getDrawable(drawableRes);
@@ -295,7 +298,7 @@
                 }
                 dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
             }
-            
+
             mAnimationState.addFrame(dr, duration);
             if (dr != null) {
                 dr.setCallback(this);
@@ -342,7 +345,7 @@
         }
 
         public void addFrame(Drawable dr, int dur) {
-            // Do not combine the following. The array index must be evaluated before 
+            // Do not combine the following. The array index must be evaluated before
             // the array is accessed because super.addChild(dr) has a side effect on mDurations.
             int pos = super.addChild(dr);
             mDurations[pos] = dur;
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index ef6c085..be940df 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -31,6 +31,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.ColorDrawable.ColorState;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Shader;
@@ -618,9 +619,11 @@
 
     @Override
     public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
-        mBitmapState.mTint = tint;
-        mBitmapState.mTintMode = tintMode;
-        computeTintFilter();
+        final BitmapState state = mBitmapState;
+        state.mTint = tint;
+        state.mTintMode = tintMode;
+
+        mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
         invalidateSelf();
     }
 
@@ -638,21 +641,6 @@
         return mBitmapState.mTintMode;
     }
 
-    private void computeTintFilter() {
-        final BitmapState state = mBitmapState;
-        if (state.mTint != null && state.mTintMode != null) {
-            final int color = state.mTint.getColorForState(getState(), 0);
-            if (mTintFilter != null) {
-                mTintFilter.setColor(color);
-                mTintFilter.setMode(state.mTintMode);
-            } else {
-                mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
-            }
-        } else {
-            mTintFilter = null;
-        }
-    }
-
     /**
      * @hide Candidate for future API inclusion
      */
@@ -679,17 +667,11 @@
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
-        final ColorStateList tint = mBitmapState.mTint;
-        if (tint != null) {
-            final int newColor = tint.getColorForState(stateSet, 0);
-            final int oldColor = mTintFilter.getColor();
-            if (oldColor != newColor) {
-                mTintFilter.setColor(newColor);
-                invalidateSelf();
-                return true;
-            }
+        final BitmapState state = mBitmapState;
+        if (state.mTint != null && state.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+            return true;
         }
-
         return false;
     }
 
@@ -946,7 +928,7 @@
             mTargetDensity = state.mTargetDensity;
         }
 
-        computeTintFilter();
+        updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
         computeBitmapSize();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 3ac9972..174de3a 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -19,10 +19,12 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
 import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
 import android.view.Gravity;
 import android.util.AttributeSet;
 
@@ -52,7 +54,7 @@
 
     public static final int HORIZONTAL = 1;
     public static final int VERTICAL = 2;
-    
+
     ClipDrawable() {
         this(null, null);
     }
@@ -111,6 +113,7 @@
 
     // overrides from Drawable.Callback
 
+    @Override
     public void invalidateDrawable(Drawable who) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -118,6 +121,7 @@
         }
     }
 
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -125,6 +129,7 @@
         }
     }
 
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -169,6 +174,11 @@
     }
 
     @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        mClipState.mDrawable.setTint(tint, tintMode);
+    }
+
+    @Override
     public int getOpacity() {
         return mClipState.mDrawable.getOpacity();
     }
@@ -197,7 +207,7 @@
 
     @Override
     public void draw(Canvas canvas) {
-        
+
         if (mClipState.mDrawable.getLevel() == 0) {
             return;
         }
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index df5ca33..3716182 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -17,6 +17,8 @@
 package android.graphics.drawable;
 
 import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -39,9 +41,13 @@
  * @attr ref android.R.styleable#ColorDrawable_color
  */
 public class ColorDrawable extends Drawable {
+    private final Paint mPaint = new Paint();
+
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_")
     private ColorState mColorState;
-    private final Paint mPaint = new Paint();
+    private ColorStateList mTint;
+    private PorterDuffColorFilter mTintFilter;
+
     private boolean mMutated;
 
     /**
@@ -84,9 +90,17 @@
 
     @Override
     public void draw(Canvas canvas) {
-        if ((mColorState.mUseColor >>> 24) != 0) {
+        final ColorFilter colorFilter = mPaint.getColorFilter();
+        if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) {
+            if (colorFilter == null) {
+                mPaint.setColorFilter(mTintFilter);
+            }
+
             mPaint.setColor(mColorState.mUseColor);
             canvas.drawRect(getBounds(), mPaint);
+
+            // Restore original color filter.
+            mPaint.setColorFilter(colorFilter);
         }
     }
 
@@ -141,16 +155,51 @@
     }
 
     /**
-     * Setting a color filter on a ColorDrawable has no effect.
+     * Sets the color filter applied to this color.
+     * <p>
+     * Only supported on version {@link android.os.Build.VERSION_CODES#L} and
+     * above. Calling this method has no effect on earlier versions.
      *
-     * @param colorFilter Ignore.
+     * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter)
      */
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
+        mPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        final ColorState state = mColorState;
+        if (state.mTint != tint || state.mTintMode != tintMode) {
+            state.mTint = tint;
+            state.mTintMode = tintMode;
+
+            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final ColorState state = mColorState;
+        if (state.mTint != null && state.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isStateful() {
+        return mTint != null && mTint.isStateful();
     }
 
     @Override
     public int getOpacity() {
+        if (mTintFilter != null || mPaint.getColorFilter() != null) {
+            return PixelFormat.TRANSLUCENT;
+        }
+
         switch (mColorState.mUseColor >>> 24) {
             case 255:
                 return PixelFormat.OPAQUE;
@@ -165,8 +214,7 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(
-                r, theme, attrs, R.styleable.ColorDrawable);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable);
         inflateStateFromTypedArray(a);
         a.recycle();
     }
@@ -225,21 +273,25 @@
     }
 
     final static class ColorState extends ConstantState {
+        int[] mThemeAttrs;
         int mBaseColor; // base color, independent of setAlpha()
         @ViewDebug.ExportedProperty
         int mUseColor;  // basecolor modulated by setAlpha()
         int mChangingConfigurations;
-        int[] mThemeAttrs;
+        ColorStateList mTint;
+        Mode mTintMode;
 
         ColorState() {
             // Empty constructor.
         }
 
         ColorState(ColorState state) {
+            mThemeAttrs = state.mThemeAttrs;
             mBaseColor = state.mBaseColor;
             mUseColor = state.mUseColor;
             mChangingConfigurations = state.mChangingConfigurations;
-            mThemeAttrs = state.mThemeAttrs;
+            mTint = state.mTint;
+            mTintMode = state.mTintMode;
         }
 
         @Override
@@ -276,6 +328,6 @@
             mColorState = state;
         }
 
-        // No local properties to initialize.
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 18e8e52..40b55a7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -17,13 +17,6 @@
 package android.graphics.drawable;
 
 import android.annotation.NonNull;
-import android.graphics.Insets;
-import android.graphics.Xfermode;
-import android.os.Trace;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -31,15 +24,19 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
+import android.graphics.Insets;
 import android.graphics.NinePatch;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.graphics.PorterDuff.Mode;
+import android.graphics.Xfermode;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.StateSet;
@@ -47,6 +44,9 @@
 import android.util.Xml;
 import android.view.View;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
@@ -209,7 +209,7 @@
      *         stored bounds of this drawable.
      *
      * @see #copyBounds()
-     * @see #copyBounds(android.graphics.Rect) 
+     * @see #copyBounds(android.graphics.Rect)
      */
     public final Rect getBounds() {
         if (mBounds == ZERO_BOUNDS_RECT) {
@@ -328,8 +328,8 @@
      * that want to support animated drawables.
      *
      * @param cb The client's Callback implementation.
-     * 
-     * @see #getCallback() 
+     *
+     * @see #getCallback()
      */
     public final void setCallback(Callback cb) {
         mCallback = new WeakReference<Callback>(cb);
@@ -338,10 +338,10 @@
     /**
      * Return the current {@link Callback} implementation attached to this
      * Drawable.
-     * 
+     *
      * @return A {@link Callback} instance or null if no callback was set.
-     * 
-     * @see #setCallback(android.graphics.drawable.Drawable.Callback) 
+     *
+     * @see #setCallback(android.graphics.drawable.Drawable.Callback)
      */
     public Callback getCallback() {
         if (mCallback != null) {
@@ -349,15 +349,15 @@
         }
         return null;
     }
-    
+
     /**
      * Use the current {@link Callback} implementation to have this Drawable
      * redrawn.  Does nothing if there is no Callback attached to the
      * Drawable.
      *
      * @see Callback#invalidateDrawable
-     * @see #getCallback() 
-     * @see #setCallback(android.graphics.drawable.Drawable.Callback) 
+     * @see #getCallback()
+     * @see #setCallback(android.graphics.drawable.Drawable.Callback)
      */
     public void invalidateSelf() {
         final Callback callback = getCallback();
@@ -931,7 +931,7 @@
             Rects only to drop them on the floor.
         */
         Rect pad = new Rect();
-        
+
         // Special stuff for compatibility mode: if the target density is not
         // the same as the display density, but the resource -is- the same as
         // the display density, then don't scale it down to the target density.
@@ -1040,6 +1040,8 @@
             drawable = new GradientDrawable();
         } else if (name.equals("vector")) {
             drawable = new VectorDrawable();
+        } else if (name.equals("animated-vector")) {
+            drawable = new AnimatedVectorDrawable();
         } else if (name.equals("scale")) {
             drawable = new ScaleDrawable();
         } else if (name.equals("clip")) {
@@ -1047,7 +1049,7 @@
         } else if (name.equals("rotate")) {
             drawable = new RotateDrawable();
         } else if (name.equals("animated-rotate")) {
-            drawable = new AnimatedRotateDrawable();            
+            drawable = new AnimatedRotateDrawable();
         } else if (name.equals("animation-list")) {
             drawable = new AnimationDrawable();
         } else if (name.equals("inset")) {
@@ -1224,6 +1226,26 @@
     }
 
     /**
+     * Ensures the tint filter is consistent with the current tint color and
+     * mode.
+     */
+    PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
+            PorterDuff.Mode tintMode) {
+        if (tint == null || tintMode == null) {
+            return null;
+        }
+
+        final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+        if (tintFilter == null) {
+            return new PorterDuffColorFilter(color, tintMode);
+        }
+
+        tintFilter.setColor(color);
+        tintFilter.setMode(tintMode);
+        return tintFilter;
+    }
+
+    /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
      */
@@ -1238,8 +1260,10 @@
     /**
      * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
      * attribute's enum value.
+     *
+     * @hide
      */
-    static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+    public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
         switch (value) {
             case 3: return Mode.SRC_OVER;
             case 5: return Mode.SRC_IN;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 2aef39f..8be6eb7 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.graphics.Canvas;
@@ -23,6 +24,7 @@
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
 import android.os.SystemClock;
 import android.util.LayoutDirection;
 import android.util.SparseArray;
@@ -151,7 +153,7 @@
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mDrawableContainerState.mHasColorFilter = true;
+        mDrawableContainerState.mHasColorFilter = (cf != null);
 
         if (mDrawableContainerState.mColorFilter != cf) {
             mDrawableContainerState.mColorFilter = cf;
@@ -162,6 +164,20 @@
         }
     }
 
+    @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        mDrawableContainerState.mHasTint = (tint != null && tintMode != null);
+
+        if (mDrawableContainerState.mTint != tint || mDrawableContainerState.mTintMode != tintMode) {
+            mDrawableContainerState.mTint = tint;
+            mDrawableContainerState.mTintMode = tintMode;
+
+            if (mCurrDrawable != null) {
+                mCurrDrawable.mutate().setTint(tint, tintMode);
+            }
+        }
+    }
+
     /**
      * Change the global fade duration when a new drawable is entering
      * the scene.
@@ -396,6 +412,8 @@
                 }
                 if (mDrawableContainerState.mHasColorFilter) {
                     d.setColorFilter(mDrawableContainerState.mColorFilter);
+                } else if (mDrawableContainerState.mHasTint) {
+                    d.setTint(mDrawableContainerState.mTint, mDrawableContainerState.mTintMode);
                 }
                 d.setVisible(isVisible(), true);
                 d.setDither(mDrawableContainerState.mDither);
@@ -566,6 +584,10 @@
         ColorFilter mColorFilter;
         boolean mHasColorFilter;
 
+        ColorStateList mTint;
+        Mode mTintMode;
+        boolean mHasTint;
+
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
@@ -588,6 +610,9 @@
                 mAutoMirrored = orig.mAutoMirrored;
                 mColorFilter = orig.mColorFilter;
                 mHasColorFilter = orig.mHasColorFilter;
+                mTint = orig.mTint;
+                mTintMode = orig.mTintMode;
+                mHasTint = orig.mHasTint;
 
                 // Cloning the following values may require creating futures.
                 mConstantPadding = orig.getConstantPadding();
@@ -741,7 +766,7 @@
             final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
             for (int i = 0; i < N; i++) {
-                final Drawable d = drawables[i]; 
+                final Drawable d = drawables[i];
                 if (d != null) {
                     if (d.canApplyTheme()) {
                         return true;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 9e0ab86..220e81c 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -19,10 +19,12 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
 import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -44,8 +46,7 @@
  * @attr ref android.R.styleable#InsetDrawable_insetTop
  * @attr ref android.R.styleable#InsetDrawable_insetBottom
  */
-public class InsetDrawable extends Drawable implements Drawable.Callback
-{
+public class InsetDrawable extends Drawable implements Drawable.Callback {
     // Most of this is copied from ScaleDrawable.
     private InsetState mInsetState;
     private final Rect mTmpRect = new Rect();
@@ -62,13 +63,13 @@
     public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
                          int insetRight, int insetBottom) {
         this(null, null);
-        
+
         mInsetState.mDrawable = drawable;
         mInsetState.mInsetLeft = insetLeft;
         mInsetState.mInsetTop = insetTop;
         mInsetState.mInsetRight = insetRight;
         mInsetState.mInsetBottom = insetBottom;
-        
+
         if (drawable != null) {
             drawable.setCallback(this);
         }
@@ -78,7 +79,7 @@
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
         int type;
-        
+
         TypedArray a = r.obtainAttributes(attrs,
                 com.android.internal.R.styleable.InsetDrawable);
 
@@ -168,7 +169,7 @@
                 | mInsetState.mChangingConfigurations
                 | mInsetState.mDrawable.getChangingConfigurations();
     }
-    
+
     @Override
     public boolean getPadding(Rect padding) {
         boolean pad = mInsetState.mDrawable.getPadding(padding);
@@ -178,7 +179,7 @@
         padding.top += mInsetState.mInsetTop;
         padding.bottom += mInsetState.mInsetBottom;
 
-        if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | 
+        if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
                     mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) {
             return true;
         } else {
@@ -217,6 +218,11 @@
         mInsetState.mDrawable.setColorFilter(cf);
     }
 
+    @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        mInsetState.mDrawable.setTint(tint, tintMode);
+    }
+
     /** {@hide} */
     @Override
     public void setLayoutDirection(int layoutDirection) {
@@ -227,7 +233,7 @@
     public int getOpacity() {
         return mInsetState.mDrawable.getOpacity();
     }
-    
+
     @Override
     public boolean isStateful() {
         return mInsetState.mDrawable.isStateful();
@@ -239,7 +245,12 @@
         onBoundsChange(getBounds());
         return changed;
     }
-    
+
+    @Override
+    protected boolean onLevelChange(int level) {
+        return mInsetState.mDrawable.setLevel(level);
+    }
+
     @Override
     protected void onBoundsChange(Rect bounds) {
         final Rect r = mTmpRect;
@@ -321,12 +332,12 @@
         public Drawable newDrawable() {
             return new InsetDrawable(this, null);
         }
-        
+
         @Override
         public Drawable newDrawable(Resources res) {
             return new InsetDrawable(this, res);
         }
-        
+
         @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 27f0a9d..5cea7c9 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -16,12 +16,14 @@
 
 package android.graphics.drawable;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
@@ -630,6 +632,15 @@
         }
     }
 
+    @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i = 0; i < N; i++) {
+            array[i].mDrawable.setTint(tint, tintMode);
+        }
+    }
+
     /**
      * Sets the opacity of this drawable directly, instead of collecting the
      * states from the layers
diff --git a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
index 9e56f67..c484094 100644
--- a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
+++ b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
@@ -27,8 +27,10 @@
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Paint.Cap;
 import android.graphics.Paint.Style;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -67,6 +69,7 @@
     private final Ring mRing;
 
     private MaterialProgressState mState;
+    private PorterDuffColorFilter mTintFilter;
 
     /** Canvas rotation in degrees. */
     private float mRotation;
@@ -106,6 +109,8 @@
             float insets = minEdge / 2.0f - state.mInnerRadius;
             ring.setInsets(insets);
         }
+
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
     @Override
@@ -118,15 +123,21 @@
     }
 
     @Override
-    protected boolean onStateChange(int[] state) {
-        boolean changed = super.onStateChange(state);
+    protected boolean onStateChange(int[] stateSet) {
+        boolean changed = super.onStateChange(stateSet);
 
-        final int color = mState.mColor.getColorForState(state, Color.TRANSPARENT);
+        final MaterialProgressState state = mState;
+        final int color = state.mColor.getColorForState(stateSet, Color.TRANSPARENT);
         if (color != mRing.getColor()) {
             mRing.setColor(color);
             changed = true;
         }
 
+        if (state.mTint != null && state.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+            changed = true;
+        }
+
         return changed;
     }
 
@@ -223,11 +234,24 @@
         return mRing.getColorFilter();
     }
 
+    @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        if (mState.mTint != tint || mState.mTintMode != tintMode) {
+            mState.mTint = tint;
+            mState.mTintMode = tintMode;
+
+            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+            invalidateSelf();
+        }
+    }
+
+    @SuppressWarnings("unused")
     private void setRotation(float rotation) {
         mRotation = rotation;
         invalidateSelf();
     }
 
+    @SuppressWarnings("unused")
     private float getRotation() {
         return mRotation;
     }
@@ -331,6 +355,8 @@
         private int mWidth = -1;
         private int mHeight = -1;
         private ColorStateList mColor = ColorStateList.valueOf(Color.TRANSPARENT);
+        private ColorStateList mTint = null;
+        private Mode mTintMode = null;
 
         public MaterialProgressState(MaterialProgressState orig) {
             if (orig != null) {
@@ -340,6 +366,8 @@
                 mWidth = orig.mWidth;
                 mHeight = orig.mHeight;
                 mColor = orig.mColor;
+                mTint = orig.mTint;
+                mTintMode = orig.mTintMode;
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index fea68ee..28335ea 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -327,25 +327,12 @@
 
     @Override
     public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
-        mNinePatchState.mTint = tint;
-        mNinePatchState.mTintMode = tintMode;
-        computeTintFilter();
-        invalidateSelf();
-    }
-
-    private void computeTintFilter() {
         final NinePatchState state = mNinePatchState;
-        if (state.mTint != null && state.mTintMode != null) {
-            final int color = state.mTint.getColorForState(getState(), 0);
-            if (mTintFilter != null) {
-                mTintFilter.setColor(color);
-                mTintFilter.setMode(state.mTintMode);
-            } else {
-                mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
-            }
-        } else {
-            mTintFilter = null;
-        }
+        state.mTint = tint;
+        state.mTintMode = tintMode;
+
+        mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+        invalidateSelf();
     }
 
     @Override
@@ -549,15 +536,10 @@
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
-        final ColorStateList tint = mNinePatchState.mTint;
-        if (tint != null) {
-            final int newColor = tint.getColorForState(stateSet, 0);
-            final int oldColor = mTintFilter.getColor();
-            if (oldColor != newColor) {
-                mTintFilter.setColor(newColor);
-                invalidateSelf();
-                return true;
-            }
+        final NinePatchState state = mNinePatchState;
+        if (state.mTint != null && state.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+            return true;
         }
 
         return false;
@@ -689,7 +671,7 @@
             mPadding = new Rect(state.mPadding);
         }
 
-        computeTintFilter();
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
         setNinePatch(state.mNinePatch);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java
index c71cda1..a82e7b9 100644
--- a/graphics/java/android/graphics/drawable/PaintDrawable.java
+++ b/graphics/java/android/graphics/drawable/PaintDrawable.java
@@ -35,7 +35,7 @@
     public PaintDrawable(int color) {
         getPaint().setColor(color);
     }
-    
+
     /**
      * Specify radius for the corners of the rectangle. If this is > 0, then the
      * drawable is drawn in a round-rectangle, rather than a rectangle.
@@ -51,7 +51,7 @@
         }
         setCornerRadii(radii);
     }
-    
+
     /**
      * Specify radii for each of the 4 corners. For each corner, the array
      * contains 2 values, [X_radius, Y_radius]. The corners are ordered
@@ -78,9 +78,9 @@
             int radius = a.getDimensionPixelSize(
                                 com.android.internal.R.styleable.DrawableCorners_radius, 0);
             setCornerRadius(radius);
-            
+
             // now check of they have any per-corner radii
-            
+
             int topLeftRadius = a.getDimensionPixelSize(
                     com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius);
             int topRightRadius = a.getDimensionPixelSize(
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index cb2d8f6..6dcda1f 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -25,7 +25,7 @@
 
 /**
  * Drawable subclass that wraps a Picture, allowing the picture to be used
- * whereever a Drawable is supported.
+ * wherever a Drawable is supported.
  */
 public class PictureDrawable extends Drawable {
 
@@ -40,7 +40,7 @@
     public PictureDrawable(Picture picture) {
         mPicture = picture;
     }
-    
+
     /**
      * Return the picture associated with the drawable. May be null.
      *
@@ -49,7 +49,7 @@
     public Picture getPicture() {
         return mPicture;
     }
-    
+
     /**
      * Associate a picture with this drawable. The picture may be null.
      *
@@ -58,7 +58,7 @@
     public void setPicture(Picture picture) {
         mPicture = picture;
     }
-    
+
     @Override
     public void draw(Canvas canvas) {
         if (mPicture != null) {
@@ -86,16 +86,16 @@
         // not sure, so be safe
         return PixelFormat.TRANSLUCENT;
     }
-    
+
     @Override
     public void setFilterBitmap(boolean filter) {}
-    
+
     @Override
     public void setDither(boolean dither) {}
-    
+
     @Override
     public void setColorFilter(ColorFilter colorFilter) {}
-    
+
     @Override
     public void setAlpha(int alpha) {}
 }
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 0d70e75..345400e 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -38,15 +38,18 @@
  */
 class Ripple {
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    private static final TimeInterpolator DECEL_INTERPOLATOR = new DecelerateInterpolator(4);
+    private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator();
 
     private static final float GLOBAL_SPEED = 1.0f;
     private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED;
-    private static final float WAVE_TOUCH_UP_ACCELERATION = 3096.0f * GLOBAL_SPEED;
-    private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.9f / GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
+    private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED;
+    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
+    private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
+    private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
 
-    private static final long RIPPLE_ENTER_DELAY = 100;
+    private static final long RIPPLE_ENTER_DELAY = 80;
 
     // Hardware animators.
     private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
@@ -311,7 +314,7 @@
     public void enter() {
         final int radiusDuration = (int)
                 (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
-        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN);
 
         final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
         radius.setAutoCancel(true);
@@ -355,7 +358,6 @@
      */
     public void exit() {
         cancelSoftwareAnimations();
-
         final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
         final float remaining;
         if (mAnimRadius != null && mAnimRadius.isRunning()) {
@@ -368,13 +370,23 @@
                 + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
         final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
 
+        // Scale the outer max opacity and opacity velocity based
+        // on the size of the outer radius
+
+        float outerSizeInfluence = MathUtils.constrain(
+                (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
+                / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
+        float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN,
+                WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence);
+
         // Determine at what time the inner and outer opacity intersect.
         // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
         // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+
         final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
-                / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+                / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
         final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
-                * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+                * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
 
         if (mCanUseHardware) {
             exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
@@ -606,4 +618,14 @@
             removeSelf();
         }
     };
+
+    /**
+    * Interpolator with a smooth log deceleration
+    */
+    private static final class LogInterpolator implements TimeInterpolator {
+        @Override
+        public float getInterpolation(float input) {
+            return 1 - (float) Math.pow(400, -input * 1.4);
+        }
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 06aeb98..8f8fa98 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -22,6 +22,8 @@
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
@@ -137,6 +139,11 @@
     }
 
     @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        mState.mDrawable.setTint(tint, tintMode);
+    }
+
+    @Override
     public int getOpacity() {
         return mState.mDrawable.getOpacity();
     }
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index f090c11..46c92fe 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -19,10 +19,12 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
 import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
 import android.view.Gravity;
 import android.util.AttributeSet;
 
@@ -188,6 +190,11 @@
     }
 
     @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        mScaleState.mDrawable.setTint(tint, tintMode);
+    }
+
+    @Override
     public int getOpacity() {
         return mScaleState.mDrawable.getOpacity();
     }
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 024f77c..beb300d 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -24,6 +24,7 @@
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
@@ -32,6 +33,7 @@
 import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -74,7 +76,7 @@
      * ShapeDrawable constructor.
      */
     public ShapeDrawable() {
-        this((ShapeState) null);
+        this(new ShapeState(null), null, null);
     }
 
     /**
@@ -83,20 +85,11 @@
      * @param s the Shape that this ShapeDrawable should be
      */
     public ShapeDrawable(Shape s) {
-        this((ShapeState) null);
+        this(new ShapeState(null), null, null);
 
         mShapeState.mShape = s;
     }
 
-    private ShapeDrawable(ShapeState state) {
-        mShapeState = new ShapeState(state);
-
-        if (state != null && state.mTint != null) {
-            final int color = state.mTint.getColorForState(getState(), 0);
-            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
-        }
-    }
-
     /**
      * Returns the Shape of this ShapeDrawable.
      */
@@ -292,31 +285,13 @@
     }
 
     @Override
-    public void setTint(ColorStateList tint, Mode tintMode) {
-        if (mShapeState.mTint != tint || mShapeState.mTintMode != tintMode) {
-            mShapeState.mTint = tint;
-            mShapeState.mTintMode = tintMode;
-            updateTintFilter();
-            invalidateSelf();
-        }
-    }
+    public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
+        final ShapeState state = mShapeState;
+        state.mTint = tint;
+        state.mTintMode = tintMode;
 
-    /**
-     * Ensures the tint filter is consistent with the current tint color and
-     * mode.
-     */
-    private void updateTintFilter() {
-        final ColorStateList tint = mShapeState.mTint;
-        final Mode tintMode = mShapeState.mTintMode;
-        if (tint != null && tintMode != null) {
-            if (mTintFilter == null) {
-                mTintFilter = new PorterDuffColorFilter(0, tintMode);
-            } else {
-                mTintFilter.setMode(tintMode);
-            }
-        } else {
-            mTintFilter = null;
-        }
+        mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+        invalidateSelf();
     }
 
     @Override
@@ -357,17 +332,11 @@
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
-        final ColorStateList tint = mShapeState.mTint;
-        if (tint != null) {
-            final int newColor = tint.getColorForState(stateSet, 0);
-            final int oldColor = mTintFilter.getColor();
-            if (oldColor != newColor) {
-                mTintFilter.setColor(newColor);
-                invalidateSelf();
-                return true;
-            }
+        final ShapeState state = mShapeState;
+        if (state.mTint != null && state.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+            return true;
         }
-
         return false;
     }
 
@@ -408,20 +377,8 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawable);
-
-        int color = mShapeState.mPaint.getColor();
-        color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color);
-        mShapeState.mPaint.setColor(color);
-
-        boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false);
-        mShapeState.mPaint.setDither(dither);
-
-        setIntrinsicWidth((int)
-                a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f));
-        setIntrinsicHeight((int)
-                a.getDimension(com.android.internal.R.styleable.ShapeDrawable_height, 0f));
-
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ShapeDrawable);
+        updateStateFromTypedArray(a);
         a.recycle();
 
         int type;
@@ -441,6 +398,38 @@
         }
     }
 
+    @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final ShapeState state = mShapeState;
+        if (state == null || state.mThemeAttrs == null) {
+            return;
+        }
+
+        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
+        final ShapeState state = mShapeState;
+        final Paint paint = state.mPaint;
+
+        int color = paint.getColor();
+        color = a.getColor(R.styleable.ShapeDrawable_color, color);
+        paint.setColor(color);
+
+        boolean dither = paint.isDither();
+        dither = a.getBoolean(R.styleable.ShapeDrawable_dither, dither);
+        paint.setDither(dither);
+
+        setIntrinsicWidth((int) a.getDimension(
+                R.styleable.ShapeDrawable_width, state.mIntrinsicWidth));
+        setIntrinsicHeight((int) a.getDimension(
+                R.styleable.ShapeDrawable_height, state.mIntrinsicHeight));
+    }
+
     private void updateShape() {
         if (mShapeState.mShape != null) {
             final Rect r = getBounds();
@@ -498,6 +487,7 @@
      * Defines the intrinsic properties of this ShapeDrawable's Shape.
      */
     final static class ShapeState extends ConstantState {
+        int[] mThemeAttrs;
         int mChangingConfigurations;
         Paint mPaint;
         Shape mShape;
@@ -511,6 +501,7 @@
 
         ShapeState(ShapeState orig) {
             if (orig != null) {
+                mThemeAttrs = orig.mThemeAttrs;
                 mPaint = orig.mPaint;
                 mShape = orig.mShape;
                 mTint = orig.mTint;
@@ -526,13 +517,23 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null;
+        }
+
+        @Override
         public Drawable newDrawable() {
-            return new ShapeDrawable(this);
+            return new ShapeDrawable(this, null, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new ShapeDrawable(this);
+            return new ShapeDrawable(this, res, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res, Theme theme) {
+            return new ShapeDrawable(this, res, theme);
         }
 
         @Override
@@ -541,6 +542,17 @@
         }
     }
 
+    private ShapeDrawable(ShapeState state, Resources res, Theme theme) {
+        if (theme != null && state.canApplyTheme()) {
+            mShapeState = new ShapeState(state);
+            applyTheme(theme);
+        } else {
+            mShapeState = state;
+        }
+
+        mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
+    }
+
     /**
      * Base class defines a factory object that is called each time the drawable
      * is resized (has a new width or height). Its resize() method returns a
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index b2fac9b..f359fdd 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -235,10 +235,10 @@
     public Drawable getStateDrawable(int index) {
         return mStateListState.getChild(index);
     }
-    
+
     /**
      * Gets the index of the drawable with the provided state set.
-     * 
+     *
      * @param stateSet the state set to look up
      * @return the index of the provided state set, or -1 if not found
      * @hide pending API council
@@ -248,7 +248,7 @@
     public int getStateDrawableIndex(int[] stateSet) {
         return mStateListState.indexOfStateSet(stateSet);
     }
-    
+
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 622e90b..4380ca4e 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -42,20 +42,20 @@
 public class TransitionDrawable extends LayerDrawable implements Drawable.Callback {
 
     /**
-     * A transition is about to start. 
+     * A transition is about to start.
      */
     private static final int TRANSITION_STARTING = 0;
-    
+
     /**
      * The transition has started and the animation is in progress
      */
     private static final int TRANSITION_RUNNING = 1;
-   
+
     /**
      * No transition will be applied
      */
     private static final int TRANSITION_NONE = 2;
-   
+
     /**
      * The current state of the transition. One of {@link #TRANSITION_STARTING},
      * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE}
@@ -101,10 +101,10 @@
     LayerState createConstantState(LayerState state, Resources res) {
         return new TransitionState((TransitionState) state, this, res);
     }
-    
+
     /**
      * Begin the second layer on top of the first layer.
-     * 
+     *
      * @param durationMillis The length of the transition in milliseconds
      */
     public void startTransition(int durationMillis) {
@@ -116,7 +116,7 @@
         mTransitionState = TRANSITION_STARTING;
         invalidateSelf();
     }
-    
+
     /**
      * Show only the first layer.
      */
@@ -184,7 +184,7 @@
                 }
                 break;
         }
-      
+
         final int alpha = mAlpha;
         final boolean crossFade = mCrossFade;
         final ChildDrawable[] array = mLayerState.mChildren;
@@ -217,7 +217,7 @@
             d.draw(canvas);
             d.setAlpha(0xFF);
         }
-        
+
         if (!done) {
             invalidateSelf();
         }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index c6c5b31..c3c1bca 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,6 +14,7 @@
 
 package android.graphics.drawable;
 
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -25,8 +26,11 @@
 import android.graphics.Path;
 import android.graphics.PathMeasure;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -40,7 +44,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.Stack;
 
 /**
@@ -135,6 +138,10 @@
 
     private final VectorDrawableState mVectorState;
 
+    private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+
+    private PorterDuffColorFilter mTintFilter;
+
     public VectorDrawable() {
         mVectorState = new VectorDrawableState(null);
     }
@@ -145,6 +152,13 @@
         if (theme != null && canApplyTheme()) {
             applyTheme(theme);
         }
+
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+    }
+
+    Object getTargetByName(String name) {
+        return mVGTargetsMap.get(name);
     }
 
     @Override
@@ -162,6 +176,11 @@
     }
 
     @Override
+    public int getAlpha() {
+        return mVectorState.mVPathRenderer.getRootAlpha();
+    }
+
+    @Override
     public void setAlpha(int alpha) {
         if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
             mVectorState.mVPathRenderer.setRootAlpha(alpha);
@@ -171,11 +190,46 @@
 
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
-        mVectorState.mVPathRenderer.setColorFilter(colorFilter);
+        final VectorDrawableState state = mVectorState;
+        if (colorFilter != null) {
+            // Color filter overrides tint.
+            mTintFilter = null;
+        } else if (state.mTint != null && state.mTintMode != null) {
+            // Restore the tint filter, if we need one.
+            final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT);
+            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+            colorFilter = mTintFilter;
+        }
+
+        state.mVPathRenderer.setColorFilter(colorFilter);
         invalidateSelf();
     }
 
     @Override
+    public void setTint(ColorStateList tint, Mode tintMode) {
+        final VectorDrawableState state = mVectorState;
+        if (state.mTint != tint || state.mTintMode != tintMode) {
+            state.mTint = tint;
+            state.mTintMode = tintMode;
+
+            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final VectorDrawableState state = mVectorState;
+        if (state.mTint != null && state.mTintMode != null) {
+            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
     public int getOpacity() {
         return PixelFormat.TRANSLUCENT;
     }
@@ -302,6 +356,9 @@
                     final VPath path = new VPath();
                     path.inflate(res, attrs, theme);
                     currentGroup.add(path);
+                    if (path.getPathName() != null) {
+                        mVGTargetsMap.put(path.getPathName(), path);
+                    }
                     noPathTag = false;
                 } else if (SHAPE_SIZE.equals(tagName)) {
                     pathRenderer.parseSize(res, attrs);
@@ -314,6 +371,9 @@
                     newChildGroup.inflate(res, attrs, theme);
                     currentGroup.mChildGroupList.add(newChildGroup);
                     groupStack.push(newChildGroup);
+                    if (newChildGroup.getGroupName() != null) {
+                        mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
+                    }
                     noGroupTag = false;
                 }
             } else if (eventType == XmlPullParser.END_TAG) {
@@ -363,7 +423,7 @@
             indent += "    ";
         }
         // Print the current node
-        Log.v(LOGTAG, indent + "current group is :" +  currentGroup.getName()
+        Log.v(LOGTAG, indent + "current group is :" +  currentGroup.getGroupName()
                 + " rotation is " + currentGroup.mRotate);
         Log.v(LOGTAG, indent + "matrix is :" +  currentGroup.getLocalMatrix().toString());
         // Then print all the children
@@ -380,6 +440,8 @@
         int mChangingConfigurations;
         VPathRenderer mVPathRenderer;
         Rect mPadding;
+        ColorStateList mTint;
+        Mode mTintMode;
 
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
@@ -387,6 +449,8 @@
                 // TODO: Make sure the constant state are handled correctly.
                 mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
                 mPadding = new Rect(copy.mPadding);
+                mTint = copy.mTint;
+                mTintMode = copy.mTintMode;
             }
         }
 
@@ -672,8 +736,7 @@
 
     }
 
-    private static class VGroup {
-        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
+    static class VGroup {
         private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
         private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
 
@@ -694,10 +757,98 @@
 
         private int[] mThemeAttrs;
 
-        private String mName = null;
+        private String mGroupName = null;
 
-        public String getName() {
-            return mName;
+        /* Getter and Setter */
+        public float getRotation() {
+            return mRotate;
+        }
+
+        public void setRotation(float rotation) {
+            if (rotation != mRotate) {
+                mRotate = rotation;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getPivotX() {
+            return mPivotX;
+        }
+
+        public void setPivotX(float pivotX) {
+            if (pivotX != mPivotX) {
+                mPivotX = pivotX;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getPivotY() {
+            return mPivotY;
+        }
+
+        public void setPivotY(float pivotY) {
+            if (pivotY != mPivotY) {
+                mPivotY = pivotY;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getScaleX() {
+            return mScaleX;
+        }
+
+        public void setScaleX(float scaleX) {
+            if (scaleX != mScaleX) {
+                mScaleX = scaleX;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getScaleY() {
+            return mScaleY;
+        }
+
+        public void setScaleY(float scaleY) {
+            if (scaleY != mScaleY) {
+                mScaleY = scaleY;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getTranslateX() {
+            return mTranslateX;
+        }
+
+        public void setTranslateX(float translateX) {
+            if (translateX != mTranslateX) {
+                mTranslateX = translateX;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getTranslateY() {
+            return mTranslateY;
+        }
+
+        public void setTranslateY(float translateY) {
+            if (translateY != mTranslateY) {
+                mTranslateY = translateY;
+                updateLocalMatrix();
+            }
+        }
+
+        public float getAlpha() {
+            return mGroupAlpha;
+        }
+
+        public void setAlpha(float groupAlpha) {
+            if (groupAlpha != mGroupAlpha) {
+                mGroupAlpha = groupAlpha;
+            }
+        }
+
+        public String getGroupName() {
+            return mGroupName;
         }
 
         public Matrix getLocalMatrix() {
@@ -705,8 +856,6 @@
         }
 
         public void add(VPath path) {
-            String id = path.getID();
-            mVGPathMap.put(id, path);
             mPathList.add(path);
          }
 
@@ -732,7 +881,7 @@
             mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
             updateLocalMatrix();
             if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
-                mName = a.getString(R.styleable.VectorDrawableGroup_name);
+                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
             }
             a.recycle();
         }
@@ -774,7 +923,7 @@
             }
 
             if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
-                mName = a.getString(R.styleable.VectorDrawableGroup_name);
+                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
             }
 
             if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
@@ -805,19 +954,15 @@
 
     }
 
-    private static class VPath {
-        private static final int MAX_STATES = 10;
-
+    static class VPath {
         private int[] mThemeAttrs;
 
         int mStrokeColor = 0;
         float mStrokeWidth = 0;
         float mStrokeOpacity = Float.NaN;
-
         int mFillColor = Color.BLACK;
         int mFillRule;
         float mFillOpacity = Float.NaN;
-
         float mTrimPathStart = 0;
         float mTrimPathEnd = 1;
         float mTrimPathOffset = 0;
@@ -828,7 +973,7 @@
         float mStrokeMiterlimit = 4;
 
         private VNode[] mNode = null;
-        private String mId;
+        private String mPathName;
 
         public VPath() {
             // Empty constructor.
@@ -841,8 +986,8 @@
             }
         }
 
-        public String getID() {
-            return mId;
+        public String getPathName() {
+            return mPathName;
         }
 
         private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
@@ -871,6 +1016,71 @@
             }
         }
 
+        /* Setters and Getters */
+        int getStroke() {
+            return mStrokeColor;
+        }
+
+        void setStroke(int strokeColor) {
+            mStrokeColor = strokeColor;
+        }
+
+        float getStrokeWidth() {
+            return mStrokeWidth;
+        }
+
+        void setStrokeWidth(float strokeWidth) {
+            mStrokeWidth = strokeWidth;
+        }
+
+        float getStrokeOpacity() {
+            return mStrokeOpacity;
+        }
+
+        void setStrokeOpacity(float strokeOpacity) {
+            mStrokeOpacity = strokeOpacity;
+        }
+
+        int getFill() {
+            return mFillColor;
+        }
+
+        void setFill(int fillColor) {
+            mFillColor = fillColor;
+        }
+
+        float getFillOpacity() {
+            return mFillOpacity;
+        }
+
+        void setFillOpacity(float fillOpacity) {
+            mFillOpacity = fillOpacity;
+        }
+
+        float getTrimPathStart() {
+            return mTrimPathStart;
+        }
+
+        void setTrimPathStart(float trimPathStart) {
+            mTrimPathStart = trimPathStart;
+        }
+
+        float getTrimPathEnd() {
+            return mTrimPathEnd;
+        }
+
+        void setTrimPathEnd(float trimPathEnd) {
+            mTrimPathEnd = trimPathEnd;
+        }
+
+        float getTrimPathOffset() {
+            return mTrimPathOffset;
+        }
+
+        void setTrimPathOffset(float trimPathOffset) {
+            mTrimPathOffset = trimPathOffset;
+        }
+
         public void inflate(Resources r, AttributeSet attrs, Theme theme) {
             final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
             final int[] themeAttrs = a.extractThemeAttrs();
@@ -883,7 +1093,7 @@
             }
 
             if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
-                mId = a.getString(R.styleable.VectorDrawablePath_name);
+                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
             }
 
             if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
@@ -966,7 +1176,7 @@
             mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
 
             if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
-                mId = a.getString(R.styleable.VectorDrawablePath_name);
+                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
             }
 
             if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 21d6caa..4a823cc 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -35,7 +35,7 @@
 /**
  * This provides the required parameters needed for initializing the
  * {@code KeyPairGenerator} that works with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
  * facility</a>. The Android KeyStore facility is accessed through a
  * {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore}
  * provider. The {@code context} passed in may be used to pop up some UI to ask
@@ -306,7 +306,7 @@
      * Builder class for {@link KeyPairGeneratorSpec} objects.
      * <p>
      * This will build a parameter spec for use with the <a href="{@docRoot}
-     * guide/topics/security/keystore.html">Android KeyStore facility</a>.
+     * training/articles/keystore.html">Android KeyStore facility</a>.
      * <p>
      * The required fields must be filled in with the builder.
      * <p>
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index b71efc4..2eeb6ad 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -24,7 +24,7 @@
 /**
  * This provides the optional parameters that can be specified for
  * {@code KeyStore} entries that work with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
  * facility</a>. The Android KeyStore facility is accessed through a
  * {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
  * provider. The {@code context} passed in may be used to pop up some UI to ask
@@ -67,7 +67,7 @@
      * Builder class for {@link KeyStoreParameter} objects.
      * <p>
      * This will build protection parameters for use with the
-     * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+     * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
      * facility</a>.
      * <p>
      * This can be used to require that KeyStore entries be stored encrypted.
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 91dda75..1b3f1fd 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1768,6 +1768,7 @@
     }
 
     mergeInfoLocked(pMergedInfo, pContents);
+    delete pContents;
     return true;
 }
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 6fd9999..402f28b 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -565,11 +565,8 @@
     // call, any texture operation will be performed on the default
     // texture (name=0)
 
-    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
-        if (mBoundTextures[i] == texture) {
-            mBoundTextures[i] = 0;
-        }
-    }
+    unbindTexture(texture);
+
     glDeleteTextures(1, &texture);
 }
 
@@ -577,6 +574,14 @@
     memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
 }
 
+void Caches::unbindTexture(GLuint texture) {
+    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
+        if (mBoundTextures[i] == texture) {
+            mBoundTextures[i] = 0;
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Scissor
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index b4b5927..83a5d9a 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -261,6 +261,11 @@
     void resetBoundTextures();
 
     /**
+     * Clear the cache of bound textures.
+     */
+    void unbindTexture(GLuint texture);
+
+    /**
      * Sets the scissor for the current surface.
      */
     bool setScissor(GLint x, GLint y, GLint width, GLint height);
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 8aa8c92..77d16ab 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -26,8 +26,25 @@
 namespace android {
 namespace uirenderer {
 
+NullDamageAccumulator NullDamageAccumulator::sInstance;
+
+NullDamageAccumulator* NullDamageAccumulator::instance() {
+    return &sInstance;
+}
+
+enum TransformType {
+    TransformInvalid = 0,
+    TransformRenderNode,
+    TransformMatrix4,
+    TransformNone,
+};
+
 struct DirtyStack {
-    const RenderNode* node;
+    TransformType type;
+    union {
+        const RenderNode* renderNode;
+        const Matrix4* matrix4;
+    };
     // When this frame is pop'd, this rect is mapped through the above transform
     // and applied to the previous (aka parent) frame
     SkRect pendingDirty;
@@ -40,9 +57,10 @@
     memset(mHead, 0, sizeof(DirtyStack));
     // Create a root that we will not pop off
     mHead->prev = mHead;
+    mHead->type = TransformNone;
 }
 
-void DamageAccumulator::pushNode(const RenderNode* node) {
+void DamageAccumulator::pushCommon() {
     if (!mHead->next) {
         DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
         nextFrame->next = 0;
@@ -50,42 +68,131 @@
         mHead->next = nextFrame;
     }
     mHead = mHead->next;
-    mHead->node = node;
     mHead->pendingDirty.setEmpty();
 }
 
-void DamageAccumulator::popNode() {
+void DamageAccumulator::pushTransform(const RenderNode* transform) {
+    pushCommon();
+    mHead->type = TransformRenderNode;
+    mHead->renderNode = transform;
+}
+
+void DamageAccumulator::pushTransform(const Matrix4* transform) {
+    pushCommon();
+    mHead->type = TransformMatrix4;
+    mHead->matrix4 = transform;
+}
+
+void DamageAccumulator::pushNullTransform() {
+    pushCommon();
+    mHead->type = TransformNone;
+}
+
+void DamageAccumulator::popTransform() {
     LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
     DirtyStack* dirtyFrame = mHead;
     mHead = mHead->prev;
-    if (!dirtyFrame->pendingDirty.isEmpty()) {
-        SkRect mappedDirty;
-        const RenderProperties& props = dirtyFrame->node->properties();
-        const SkMatrix* transform = props.getTransformMatrix();
-        if (transform && !transform->isIdentity()) {
-            transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty);
-        } else {
-            mappedDirty = dirtyFrame->pendingDirty;
+    switch (dirtyFrame->type) {
+    case TransformRenderNode:
+        applyRenderNodeTransform(dirtyFrame);
+        break;
+    case TransformMatrix4:
+        applyMatrix4Transform(dirtyFrame);
+        break;
+    case TransformNone:
+        mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+        break;
+    default:
+        LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
+    }
+}
+
+static inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
+    if (in.isEmpty()) return;
+    Rect temp(in);
+    matrix->mapRect(temp);
+    out->join(RECT_ARGS(temp));
+}
+
+void DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
+    mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
+}
+
+static inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
+    if (in.isEmpty()) return;
+    const SkMatrix* transform = props.getTransformMatrix();
+    SkRect temp(in);
+    if (transform && !transform->isIdentity()) {
+        transform->mapRect(&temp);
+    }
+    temp.offset(props.getLeft(), props.getTop());
+    out->join(temp);
+}
+
+static DirtyStack* findParentRenderNode(DirtyStack* frame) {
+    while (frame->prev != frame) {
+        frame = frame->prev;
+        if (frame->type == TransformRenderNode) {
+            return frame;
         }
-        if (CC_LIKELY(mHead->node)) {
-            const RenderProperties& parentProps = mHead->node->properties();
-            mappedDirty.offset(props.getLeft() - parentProps.getScrollX(),
-                    props.getTop() - parentProps.getScrollY());
-            if (props.getClipToBounds()) {
-                if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) {
-                    mappedDirty.setEmpty();
-                }
+    }
+    return NULL;
+}
+
+static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
+    if (frame) {
+        while (frame->prev != frame) {
+            frame = frame->prev;
+            if (frame->type == TransformRenderNode
+                    && frame->renderNode->hasProjectionReceiver()) {
+                return frame;
             }
-            if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) {
-                // TODO: Can we better bound the shadow damage area? For now
-                // match the old damageShadowReceiver() path and just dirty
-                // the entire parent bounds
-                mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight());
-            }
-        } else {
-            mappedDirty.offset(props.getLeft(), props.getTop());
         }
-        dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom);
+    }
+    return NULL;
+}
+
+static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
+    SkRect* rect = &frame->pendingDirty;
+    while (frame != end) {
+        if (frame->type == TransformRenderNode) {
+            mapRect(frame->renderNode->properties(), *rect, rect);
+        } else {
+            mapRect(frame->matrix4, *rect, rect);
+        }
+        frame = frame->prev;
+    }
+}
+
+void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
+    if (frame->pendingDirty.isEmpty()) {
+        return;
+    }
+
+    const RenderProperties& props = frame->renderNode->properties();
+
+    // Perform clipping
+    if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) {
+        if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
+            frame->pendingDirty.setEmpty();
+        }
+    }
+
+    // apply all transforms
+    mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
+
+    // project backwards if necessary
+    if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
+        // First, find our parent RenderNode:
+        DirtyStack* parentNode = findParentRenderNode(frame);
+        // Find our parent's projection receiver, which is what we project onto
+        DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
+        if (projectionReceiver) {
+            applyTransforms(frame, projectionReceiver);
+            projectionReceiver->pendingDirty.join(frame->pendingDirty);
+        }
+
+        frame->pendingDirty.setEmpty();
     }
 }
 
@@ -93,6 +200,10 @@
     mHead->pendingDirty.join(left, top, right, bottom);
 }
 
+void DamageAccumulator::peekAtDirty(SkRect* dest) {
+    *dest = mHead->pendingDirty;
+}
+
 void DamageAccumulator::finish(SkRect* totalDirty) {
     LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
     // Root node never has a transform, so this is the fully mapped dirty rect
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index c62a351..fc9b41b 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -16,6 +16,7 @@
 #ifndef DAMAGEACCUMULATOR_H
 #define DAMAGEACCUMULATOR_H
 
+#include <cutils/compiler.h>
 #include <utils/LinearAllocator.h>
 
 #include <SkMatrix.h>
@@ -28,8 +29,21 @@
 
 struct DirtyStack;
 class RenderNode;
+class Matrix4;
 
-class DamageAccumulator {
+class IDamageAccumulator {
+public:
+    virtual void pushTransform(const RenderNode* transform) = 0;
+    virtual void pushTransform(const Matrix4* transform) = 0;
+    virtual void pushNullTransform() = 0;
+    virtual void popTransform() = 0;
+    virtual void dirty(float left, float top, float right, float bottom) = 0;
+    virtual void peekAtDirty(SkRect* dest) = 0;
+protected:
+    virtual ~IDamageAccumulator() {}
+};
+
+class DamageAccumulator : public IDamageAccumulator {
     PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
 public:
     DamageAccumulator();
@@ -37,20 +51,52 @@
 
     // Push a transform node onto the stack. This should be called prior
     // to any dirty() calls. Subsequent calls to dirty()
-    // will be affected by the node's transform when popNode() is called.
-    void pushNode(const RenderNode* node);
+    // will be affected by the transform when popTransform() is called.
+    virtual void pushTransform(const RenderNode* transform);
+    virtual void pushTransform(const Matrix4* transform);
+    // This is used in combination with peekAtDirty to inspect the damage
+    // area of a subtree
+    virtual void pushNullTransform();
+
     // Pops a transform node from the stack, propagating the dirty rect
-    // up to the parent node.
-    void popNode();
-    void dirty(float left, float top, float right, float bottom);
+    // up to the parent node. Returns the IDamageTransform that was just applied
+    virtual void popTransform();
+
+    virtual void dirty(float left, float top, float right, float bottom);
+
+    // Returns the current dirty area, *NOT* transformed by pushed transforms
+    virtual void peekAtDirty(SkRect* dest);
 
     void finish(SkRect* totalDirty);
 
 private:
+    void pushCommon();
+    void applyMatrix4Transform(DirtyStack* frame);
+    void applyRenderNodeTransform(DirtyStack* frame);
+
     LinearAllocator mAllocator;
     DirtyStack* mHead;
 };
 
+class NullDamageAccumulator : public IDamageAccumulator {
+    PREVENT_COPY_AND_ASSIGN(NullDamageAccumulator);
+public:
+    virtual void pushTransform(const RenderNode* transform) { }
+    virtual void pushTransform(const Matrix4* transform) { }
+    virtual void pushNullTransform() { }
+    virtual void popTransform() { }
+    virtual void dirty(float left, float top, float right, float bottom) { }
+    virtual void peekAtDirty(SkRect* dest) { dest->setEmpty(); }
+
+    ANDROID_API static NullDamageAccumulator* instance();
+
+private:
+    NullDamageAccumulator() {}
+    ~NullDamageAccumulator() {}
+
+    static NullDamageAccumulator sInstance;
+};
+
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d494c4c..8e99b9a 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -27,8 +27,7 @@
 }
 
 DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
-        : mDisplayList(0)
-        , mSurfaceTexture(0)
+        : mSurfaceTexture(0)
         , mTransform(0)
         , mNeedsGLContextAttach(false)
         , mUpdateTexImage(false)
@@ -41,7 +40,6 @@
     mColorFilter = SkSafeRef(mLayer->getColorFilter());
     mAlpha = mLayer->getAlpha();
     mMode = mLayer->getMode();
-    mDirtyRect.setEmpty();
 
     if (!mDestroyer) {
         mDestroyer = defaultLayerDestroyer;
@@ -60,37 +58,13 @@
     SkRefCnt_SafeAssign(mColorFilter, colorFilter);
 }
 
-void DeferredLayerUpdater::setDisplayList(RenderNode* displayList,
-        int left, int top, int right, int bottom) {
-    mDisplayList = displayList;
-    if (mDirtyRect.isEmpty()) {
-        mDirtyRect.set(left, top, right, bottom);
-    } else {
-        mDirtyRect.unionWith(Rect(left, top, right, bottom));
-    }
-}
-
 bool DeferredLayerUpdater::apply(TreeInfo& info) {
     bool success = true;
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
     mLayer->setAlpha(mAlpha, mMode);
 
-    if (mDisplayList.get()) {
-        if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
-            success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
-        }
-        mLayer->setBlend(mBlend);
-        // TODO: Use DamageAccumulator to get the damage area for the layer's
-        // subtree to only update that part of the layer. Do this as part of
-        // reworking layers to be a RenderProperty instead of a View-managed object
-        mDirtyRect.set(0, 0, mWidth, mHeight);
-        mDisplayList->prepareTree(info);
-        mLayer->updateDeferred(mDisplayList.get(),
-                mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
-        mDirtyRect.setEmpty();
-        mDisplayList = 0;
-    } else if (mSurfaceTexture.get()) {
+    if (mSurfaceTexture.get()) {
         if (mNeedsGLContextAttach) {
             mNeedsGLContextAttach = false;
             mSurfaceTexture->attachToContext(mLayer->getTexture());
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index b7cfe80..5082271 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -74,9 +74,6 @@
         mTransform = matrix ? new SkMatrix(*matrix) : 0;
     }
 
-    ANDROID_API void setDisplayList(RenderNode* displayList,
-                int left, int top, int right, int bottom);
-
     ANDROID_API void setPaint(const SkPaint* paint);
 
     ANDROID_API bool apply(TreeInfo& info);
@@ -94,11 +91,6 @@
     int mAlpha;
     SkXfermode::Mode mMode;
 
-    // Layer type specific properties
-    // displayList and surfaceTexture are mutually exclusive, only 1 may be set
-    // dirtyRect is only valid if displayList is set
-    sp<RenderNode> mDisplayList;
-    Rect mDirtyRect;
     sp<GLConsumer> mSurfaceTexture;
     SkMatrix* mTransform;
     bool mNeedsGLContextAttach;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 6a2ef2a..1002e13 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -185,6 +185,7 @@
 }
 
 void Layer::clearTexture() {
+    caches.unbindTexture(texture.id);
     texture.id = 0;
 }
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index df9aee5..a5fd375 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -334,8 +334,10 @@
 
 void LayerRenderer::flushLayer(Layer* layer) {
 #ifdef GL_EXT_discard_framebuffer
+    if (!layer) return;
+
     GLuint fbo = layer->getFbo();
-    if (layer && fbo) {
+    if (fbo) {
         // If possible, discard any enqueud operations on deferred
         // rendering architectures
         if (Extensions::getInstance().hasDiscardFramebuffer()) {
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 2268386..9f2014f 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -417,6 +417,8 @@
 }
 
 void Matrix4::mapRect(Rect& r) const {
+    if (isIdentity()) return;
+
     if (isSimple()) {
         MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
         MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index e33a001..1c5c578 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -147,6 +147,7 @@
             data[kTranslateX] += x;
             data[kTranslateY] += y;
             data[kTranslateZ] += z;
+            mType |= kTypeUnknown;
         } else {
             // Doing a translation will only affect the translate bit of the type
             // Save the type
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index c9921ba..310b107 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -57,17 +57,26 @@
 #define ROUND_CAP_THRESH 0.25f
 #define PI 3.1415926535897932f
 
+// temporary error thresholds
+#define ERROR_DEPTH 20
+#define ERROR_SCALE 1e10
+#define ERROR_SQR_INV_THRESH 1e-20
+
 void PathTessellator::extractTessellationScales(const Matrix4& transform,
         float* scaleX, float* scaleY) {
-    *scaleX = 1.0f;
-    *scaleY = 1.0f;
-    if (CC_UNLIKELY(!transform.isPureTranslate())) {
+    if (CC_LIKELY(transform.isPureTranslate())) {
+        *scaleX = 1.0f;
+        *scaleY = 1.0f;
+    } else {
         float m00 = transform.data[Matrix4::kScaleX];
         float m01 = transform.data[Matrix4::kSkewY];
         float m10 = transform.data[Matrix4::kSkewX];
         float m11 = transform.data[Matrix4::kScaleY];
         *scaleX = sqrt(m00 * m00 + m01 * m01);
         *scaleY = sqrt(m10 * m10 + m11 * m11);
+
+        LOG_ALWAYS_FATAL_IF(*scaleX > ERROR_SCALE || *scaleY > ERROR_SCALE,
+                "scales %e x %e too large for tessellation", *scaleX, *scaleY);
     }
 }
 
@@ -92,10 +101,12 @@
 public:
     PaintInfo(const SkPaint* paint, const mat4& transform) :
             style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
-            inverseScaleX(1.0f), inverseScaleY(1.0f),
             halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
         // compute inverse scales
-        if (CC_UNLIKELY(!transform.isPureTranslate())) {
+        if (CC_LIKELY(transform.isPureTranslate())) {
+            inverseScaleX = 1.0f;
+            inverseScaleY = 1.0f;
+        } else {
             float scaleX, scaleY;
             PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
             inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
@@ -922,6 +933,9 @@
         Vector<Vertex>& outputVertices) {
     ATRACE_CALL();
 
+    LOG_ALWAYS_FATAL_IF(sqrInvScaleX < ERROR_SQR_INV_THRESH || sqrInvScaleY < ERROR_SQR_INV_THRESH,
+            "Invalid scale factors used for approx %e, %e", sqrInvScaleX, sqrInvScaleY);
+
     // TODO: to support joins other than sharp miter, join vertices should be labelled in the
     // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
     SkPath::Iter iter(path, forceClose);
@@ -979,7 +993,10 @@
         float p1x, float p1y, float c1x, float c1y,
         float p2x, float p2y, float c2x, float c2y,
         float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
-        Vector<Vertex>& outputVertices) {
+        Vector<Vertex>& outputVertices, int depth) {
+    LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR DEPTH exceeded: cubic approx, invscale %e x %e, vertcount %d",
+            sqrInvScaleX, sqrInvScaleY, outputVertices.size());
+
     float dx = p2x - p1x;
     float dy = p2y - p1y;
     float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -987,7 +1004,6 @@
     float d = d1 + d2;
 
     // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
-
     if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
         // below thresh, draw line by adding endpoint
         pushToVector(outputVertices, p2x, p2y);
@@ -1012,11 +1028,11 @@
         recursiveCubicBezierVertices(
                 p1x, p1y, p1c1x, p1c1y,
                 mx, my, p1c1c2x, p1c1c2y,
-                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
         recursiveCubicBezierVertices(
                 mx, my, p2c1c2x, p2c1c2y,
                 p2x, p2y, p2c2x, p2c2y,
-                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
     }
 }
 
@@ -1025,7 +1041,10 @@
         float bx, float by,
         float cx, float cy,
         float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
-        Vector<Vertex>& outputVertices) {
+        Vector<Vertex>& outputVertices, int depth) {
+    LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR_DEPTH exceeded: quadratic approx, invscale %e x %e, vertcount %d",
+            sqrInvScaleX, sqrInvScaleY, outputVertices.size());
+
     float dx = bx - ax;
     float dy = by - ay;
     float d = (cx - bx) * dy - (cy - by) * dx;
@@ -1044,9 +1063,9 @@
         float my = (acy + bcy) * 0.5f;
 
         recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
-                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
         recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
-                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
     }
 }
 
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index f033470..8ac9a3b 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -105,7 +105,7 @@
             float bx, float by,
             float cx, float cy,
             float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
-            Vector<Vertex> &outputVertices);
+            Vector<Vertex> &outputVertices, int depth = 0);
 
 /*
   endpoints p1, p2
@@ -117,7 +117,7 @@
             float p2x, float p2y,
             float c2x, float c2y,
             float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
-            Vector<Vertex> &outputVertices);
+            Vector<Vertex> &outputVertices, int depth = 0);
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c2f6df8..fc51170 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -15,6 +15,7 @@
  */
 
 #define ATRACE_TAG ATRACE_TAG_VIEW
+#define LOG_TAG "RenderNode"
 
 #include "RenderNode.h"
 
@@ -29,6 +30,8 @@
 #include "Debug.h"
 #include "DisplayListOp.h"
 #include "DisplayListLogBuffer.h"
+#include "LayerRenderer.h"
+#include "OpenGLRenderer.h"
 #include "utils/MathUtils.h"
 
 namespace android {
@@ -58,12 +61,14 @@
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0)
-        , mNeedsAnimatorsSync(false) {
+        , mNeedsAnimatorsSync(false)
+        , mLayer(0) {
 }
 
 RenderNode::~RenderNode() {
     delete mDisplayListData;
     delete mStagingDisplayListData;
+    LayerRenderer::destroyLayerDeferred(mLayer);
 }
 
 void RenderNode::setStagingDisplayList(DisplayListData* data) {
@@ -111,36 +116,85 @@
     prepareTreeImpl(info);
 }
 
-static inline void pushNode(RenderNode* self, TreeInfo& info) {
-    if (info.damageAccumulator) {
-        info.damageAccumulator->pushNode(self);
-    }
-}
-
-static inline void popNode(TreeInfo& info) {
-    if (info.damageAccumulator) {
-        info.damageAccumulator->popNode();
-    }
-}
-
 void RenderNode::damageSelf(TreeInfo& info) {
-    if (info.damageAccumulator && isRenderable() && properties().getAlpha() > 0) {
-        info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+    if (isRenderable() && properties().getAlpha() > 0) {
+        if (properties().getClipDamageToBounds()) {
+            info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+        } else {
+            // Hope this is big enough?
+            // TODO: Get this from the display list ops or something
+            info.damageAccumulator->dirty(INT_MIN, INT_MIN, INT_MAX, INT_MAX);
+        }
+    }
+}
+
+void RenderNode::prepareLayer(TreeInfo& info) {
+    LayerType layerType = properties().layerProperties().type();
+    if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+        // We push a null transform here as we don't care what the existing dirty
+        // area is, only what our display list dirty is as well as our children's
+        // dirty area
+        info.damageAccumulator->pushNullTransform();
+    }
+}
+
+void RenderNode::pushLayerUpdate(TreeInfo& info) {
+    LayerType layerType = properties().layerProperties().type();
+    // If we are not a layer OR we cannot be rendered (eg, view was detached)
+    // we need to destroy any Layers we may have had previously
+    if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+        if (layerType == kLayerTypeRenderLayer) {
+            info.damageAccumulator->popTransform();
+        }
+        if (CC_UNLIKELY(mLayer)) {
+            LayerRenderer::destroyLayer(mLayer);
+            mLayer = NULL;
+        }
+        return;
+    }
+
+    if (!mLayer) {
+        mLayer = LayerRenderer::createRenderLayer(getWidth(), getHeight());
+        applyLayerPropertiesToLayer(info);
+        damageSelf(info);
+    } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
+        LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight());
+        damageSelf(info);
+    }
+
+    SkRect dirty;
+    info.damageAccumulator->peekAtDirty(&dirty);
+    info.damageAccumulator->popTransform();
+
+    if (!dirty.isEmpty()) {
+        mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
+    }
+    // This is not inside the above if because we may have called
+    // updateDeferred on a previous prepare pass that didn't have a renderer
+    if (info.renderer && mLayer->deferredUpdateScheduled) {
+        info.renderer->pushLayerUpdate(mLayer);
     }
 }
 
 void RenderNode::prepareTreeImpl(TreeInfo& info) {
-    pushNode(this, info);
+    info.damageAccumulator->pushTransform(this);
     if (info.mode == TreeInfo::MODE_FULL) {
-        pushStagingChanges(info);
+        pushStagingPropertiesChanges(info);
         evaluateAnimations(info);
     } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
-        pushStagingChanges(info);
+        pushStagingPropertiesChanges(info);
     } else if (info.mode == TreeInfo::MODE_RT_ONLY) {
         evaluateAnimations(info);
     }
+
+    prepareLayer(info);
+    if (info.mode == TreeInfo::MODE_FULL) {
+        pushStagingDisplayListChanges(info);
+    }
     prepareSubTree(info, mDisplayListData);
-    popNode(info);
+    pushLayerUpdate(info);
+
+    info.damageAccumulator->popTransform();
 }
 
 class PushAnimatorsFunctor {
@@ -157,7 +211,7 @@
     TreeInfo& mInfo;
 };
 
-void RenderNode::pushStagingChanges(TreeInfo& info) {
+void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
     // Push the animators first so that setupStartValueIfNecessary() is called
     // before properties() is trampled by stagingProperties(), as they are
     // required by some animators.
@@ -173,16 +227,29 @@
     if (mDirtyPropertyFields) {
         mDirtyPropertyFields = 0;
         damageSelf(info);
-        popNode(info);
+        info.damageAccumulator->popTransform();
         mProperties = mStagingProperties;
-        pushNode(this, info);
+        applyLayerPropertiesToLayer(info);
         // We could try to be clever and only re-damage if the matrix changed.
         // However, we don't need to worry about that. The cost of over-damaging
         // here is only going to be a single additional map rect of this node
         // plus a rect join(). The parent's transform (and up) will only be
         // performed once.
+        info.damageAccumulator->pushTransform(this);
         damageSelf(info);
     }
+}
+
+void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
+    if (CC_LIKELY(!mLayer)) return;
+
+    const LayerProperties& props = properties().layerProperties();
+    mLayer->setAlpha(props.alpha(), props.xferMode());
+    mLayer->setColorFilter(props.colorFilter());
+    mLayer->setBlend(props.needsBlending());
+}
+
+void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
     if (mNeedsDisplayListDataSync) {
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
@@ -217,7 +284,7 @@
     // property push and just damage self before and after animators are run
 
     damageSelf(info);
-    popNode(info);
+    info.damageAccumulator->popTransform();
 
     AnimateFunctor functor(this, info);
     std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
@@ -226,7 +293,7 @@
     mProperties.updateMatrix();
     info.out.hasAnimations |= mAnimators.size();
 
-    pushNode(this, info);
+    info.damageAccumulator->pushTransform(this);
     damageSelf(info);
 }
 
@@ -243,8 +310,11 @@
             info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
         }
         for (size_t i = 0; i < subtree->children().size(); i++) {
-            RenderNode* childNode = subtree->children()[i]->mDisplayList;
+            DrawDisplayListOp* op = subtree->children()[i];
+            RenderNode* childNode = op->mDisplayList;
+            info.damageAccumulator->pushTransform(&op->mTransformFromParent);
             childNode->prepareTreeImpl(info);
+            info.damageAccumulator->popTransform();
         }
     }
 }
@@ -276,9 +346,10 @@
             renderer.concatMatrix(*properties().getTransformMatrix());
         }
     }
-    bool clipToBoundsNeeded = properties().getCaching() ? false : properties().getClipToBounds();
+    const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+    bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
     if (properties().getAlpha() < 1) {
-        if (properties().getCaching()) {
+        if (isLayer) {
             renderer.setOverrideLayerAlpha(properties().getAlpha());
         } else if (!properties().getHasOverlappingRendering()) {
             renderer.scaleAlpha(properties().getAlpha());
@@ -693,8 +764,14 @@
  */
 template <class T>
 void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+    const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+    // If we are updating the contents of mLayer, we don't want to apply any of
+    // the RenderNode's properties to this issueOperations pass. Those will all
+    // be applied when the layer is drawn, aka when this is true.
+    const bool useViewProperties = (!mLayer || drawLayer);
+
     const int level = handler.level();
-    if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
+    if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
         return;
     }
@@ -716,7 +793,9 @@
     DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
 
-    setViewProperties<T>(renderer, handler);
+    if (useViewProperties) {
+        setViewProperties<T>(renderer, handler);
+    }
 
     bool quickRejected = properties().getClipToBounds()
             && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -725,31 +804,36 @@
             renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
         }
 
-        Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
-        buildZSortedChildList(zTranslatedNodes);
+        if (drawLayer) {
+            handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+                    renderer.getSaveCount() - 1, properties().getClipToBounds());
+        } else {
+            Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+            buildZSortedChildList(zTranslatedNodes);
 
-        // for 3d root, draw children with negative z values
-        issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+            // for 3d root, draw children with negative z values
+            issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
 
-        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
-        const int saveCountOffset = renderer.getSaveCount() - 1;
-        const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
-        for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
-            DisplayListOp *op = mDisplayListData->displayListOps[i];
+            DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+            const int saveCountOffset = renderer.getSaveCount() - 1;
+            const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
+            for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+                DisplayListOp *op = mDisplayListData->displayListOps[i];
 
-#if DEBUG_DISPLAY_LIST
-            op->output(level + 1);
-#endif
-            logBuffer.writeCommand(level, op->name());
-            handler(op, saveCountOffset, properties().getClipToBounds());
+    #if DEBUG_DISPLAY_LIST
+                op->output(level + 1);
+    #endif
+                logBuffer.writeCommand(level, op->name());
+                handler(op, saveCountOffset, properties().getClipToBounds());
 
-            if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
-                issueOperationsOfProjectedChildren(renderer, handler);
+                if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
+                    issueOperationsOfProjectedChildren(renderer, handler);
+                }
             }
-        }
 
-        // for 3d root, draw children with positive z values
-        issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+            // for 3d root, draw children with positive z values
+            issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+        }
     }
 
     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 393d4ea..b2fe849 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -39,6 +39,7 @@
 
 #include <androidfw/ResourceTypes.h>
 
+#include "DamageAccumulator.h"
 #include "Debug.h"
 #include "Matrix.h"
 #include "DeferredDisplayList.h"
@@ -125,6 +126,10 @@
         return mDisplayListData && mDisplayListData->hasDrawOps;
     }
 
+    bool hasProjectionReceiver() const {
+        return mDisplayListData && mDisplayListData->projectionReceiveIndex >= 0;
+    }
+
     const char* getName() const {
         return mName.string();
     }
@@ -249,9 +254,13 @@
     };
 
     void prepareTreeImpl(TreeInfo& info);
-    void pushStagingChanges(TreeInfo& info);
+    void pushStagingPropertiesChanges(TreeInfo& info);
+    void pushStagingDisplayListChanges(TreeInfo& info);
     void evaluateAnimations(TreeInfo& info);
     void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+    void applyLayerPropertiesToLayer(TreeInfo& info);
+    void prepareLayer(TreeInfo& info);
+    void pushLayerUpdate(TreeInfo& info);
 
     String8 mName;
 
@@ -267,6 +276,10 @@
     std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
     std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
 
+    // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
+    // being in ~RenderNode() which may happen on any thread.
+    Layer* mLayer;
+
     /**
      * Draw time state - these properties are only set and used during rendering
      */
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 6163df5..8848b2f 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -21,16 +21,59 @@
 #include <utils/Trace.h>
 
 #include <SkCanvas.h>
+#include <SkColorFilter.h>
 #include <SkMatrix.h>
 #include <SkPath.h>
 #include <SkPathOps.h>
 
 #include "Matrix.h"
+#include "OpenGLRenderer.h"
 #include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
 
+LayerProperties::LayerProperties()
+        : mType(kLayerTypeNone)
+        , mColorFilter(NULL) {
+    reset();
+}
+
+LayerProperties::~LayerProperties() {
+    setType(kLayerTypeNone);
+}
+
+void LayerProperties::reset() {
+    mOpaque = false;
+    setFromPaint(NULL);
+}
+
+bool LayerProperties::setColorFilter(SkColorFilter* filter) {
+   if (mColorFilter == filter) return false;
+   SkRefCnt_SafeAssign(mColorFilter, filter);
+   return true;
+}
+
+bool LayerProperties::setFromPaint(const SkPaint* paint) {
+    bool changed = false;
+    SkXfermode::Mode mode;
+    int alpha;
+    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+    changed |= setAlpha(static_cast<uint8_t>(alpha));
+    changed |= setXferMode(mode);
+    changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+    return changed;
+}
+
+LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
+    setType(other.type());
+    setOpaque(other.opaque());
+    setAlpha(other.alpha());
+    setXferMode(other.xferMode());
+    setColorFilter(other.colorFilter());
+    return *this;
+}
+
 RenderProperties::PrimitiveFields::PrimitiveFields()
         : mClipToBounds(true)
         , mProjectBackwards(false)
@@ -44,10 +87,8 @@
         , mPivotX(0), mPivotY(0)
         , mLeft(0), mTop(0), mRight(0), mBottom(0)
         , mWidth(0), mHeight(0)
-        , mScrollX(0), mScrollY(0)
         , mPivotExplicitlySet(false)
-        , mMatrixOrPivotDirty(false)
-        , mCaching(false) {
+        , mMatrixOrPivotDirty(false) {
 }
 
 RenderProperties::ComputedFields::ComputedFields()
@@ -74,6 +115,7 @@
         setStaticMatrix(other.getStaticMatrix());
         setAnimationMatrix(other.getAnimationMatrix());
         setCameraDistance(other.getCameraDistance());
+        mLayerProperties = other.layerProperties();
 
         // Force recalculation of the matrix, since other's dirty bit may be clear
         mPrimitiveFields.mMatrixOrPivotDirty = true;
@@ -104,9 +146,9 @@
         }
     }
 
-    bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
+    bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
     if (mPrimitiveFields.mAlpha < 1) {
-        if (mPrimitiveFields.mCaching) {
+        if (layerProperties().type() != kLayerTypeNone) {
             ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         } else if (!mPrimitiveFields.mHasOverlappingRendering) {
             ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index c294f38..227d56e 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -21,6 +21,7 @@
 #include <vector>
 #include <cutils/compiler.h>
 #include <androidfw/ResourceTypes.h>
+#include <utils/Log.h>
 
 #include <SkCamera.h>
 #include <SkMatrix.h>
@@ -30,8 +31,10 @@
 #include "Rect.h"
 #include "RevealClip.h"
 #include "Outline.h"
+#include "utils/MathUtils.h"
 
 class SkBitmap;
+class SkColorFilter;
 class SkPaint;
 
 namespace android {
@@ -39,15 +42,95 @@
 
 class Matrix4;
 class RenderNode;
+class RenderProperties;
 
 // The __VA_ARGS__ will be executed if a & b are not equal
 #define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
 #define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
 
+// Keep in sync with View.java:LAYER_TYPE_*
+enum LayerType {
+    kLayerTypeNone = 0,
+    // Although we cannot build the software layer directly (must be done at
+    // record time), this information is used when applying alpha.
+    kLayerTypeSoftware = 1,
+    kLayerTypeRenderLayer = 2,
+    // TODO: LayerTypeSurfaceTexture? Maybe?
+};
+
+class ANDROID_API LayerProperties {
+public:
+    bool setType(LayerType type) {
+        if (RP_SET(mType, type)) {
+            reset();
+            return true;
+        }
+        return false;
+    }
+
+    LayerType type() const {
+        return mType;
+    }
+
+    bool setOpaque(bool opaque) {
+        return RP_SET(mOpaque, opaque);
+    }
+
+    bool opaque() const {
+        return mOpaque;
+    }
+
+    bool setAlpha(uint8_t alpha) {
+        return RP_SET(mAlpha, alpha);
+    }
+
+    uint8_t alpha() const {
+        return mAlpha;
+    }
+
+    bool setXferMode(SkXfermode::Mode mode) {
+        return RP_SET(mMode, mode);
+    }
+
+    SkXfermode::Mode xferMode() const {
+        return mMode;
+    }
+
+    bool setColorFilter(SkColorFilter* filter);
+
+    SkColorFilter* colorFilter() const {
+        return mColorFilter;
+    }
+
+    // Sets alpha, xfermode, and colorfilter from an SkPaint
+    // paint may be NULL, in which case defaults will be set
+    bool setFromPaint(const SkPaint* paint);
+
+    bool needsBlending() const {
+        return !opaque() || alpha() < 255;
+    }
+
+    LayerProperties& operator=(const LayerProperties& other);
+
+private:
+    LayerProperties();
+    ~LayerProperties();
+    void reset();
+
+    friend class RenderProperties;
+
+    LayerType mType;
+    // Whether or not that Layer's content is opaque, doesn't include alpha
+    bool mOpaque;
+    uint8_t mAlpha;
+    SkXfermode::Mode mMode;
+    SkColorFilter* mColorFilter;
+};
+
 /*
  * Data structure that holds the properties for a RenderNode
  */
-class RenderProperties {
+class ANDROID_API RenderProperties {
 public:
     RenderProperties();
     virtual ~RenderProperties();
@@ -200,6 +283,7 @@
     }
 
     bool setScaleX(float scaleX) {
+        LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", scaleX);
         return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
     }
 
@@ -208,6 +292,7 @@
     }
 
     bool setScaleY(float scaleY) {
+        LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY);
         return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
     }
 
@@ -366,26 +451,6 @@
         return false;
     }
 
-    bool setScrollX(int scrollX) {
-        return RP_SET(mPrimitiveFields.mScrollX, scrollX);
-    }
-
-    bool setScrollY(int scrollY) {
-        return RP_SET(mPrimitiveFields.mScrollY, scrollY);
-    }
-
-    int getScrollX() const {
-        return mPrimitiveFields.mScrollX;
-    }
-
-    int getScrollY() const {
-        return mPrimitiveFields.mScrollY;
-    }
-
-    bool setCaching(bool caching) {
-        return RP_SET(mPrimitiveFields.mCaching, caching);
-    }
-
     int getWidth() const {
         return mPrimitiveFields.mWidth;
     }
@@ -412,10 +477,6 @@
         return mComputedFields.mTransformMatrix;
     }
 
-    bool getCaching() const {
-        return mPrimitiveFields.mCaching;
-    }
-
     bool getClipToBounds() const {
         return mPrimitiveFields.mClipToBounds;
     }
@@ -438,7 +499,7 @@
 
     void debugOutputProperties(const int level) const;
 
-    ANDROID_API void updateMatrix();
+    void updateMatrix();
 
     bool hasClippingPath() const {
         return mPrimitiveFields.mRevealClip.willClip();
@@ -461,6 +522,23 @@
         return mPrimitiveFields.mRevealClip;
     }
 
+    const LayerProperties& layerProperties() const {
+        return mLayerProperties;
+    }
+
+    LayerProperties& mutateLayerProperties() {
+        return mLayerProperties;
+    }
+
+    // Returns true if damage calculations should be clipped to bounds
+    // TODO: Figure out something better for getZ(), as children should still be
+    // clipped to this RP's bounds. But as we will damage -INT_MAX to INT_MAX
+    // for this RP's getZ() anyway, this can be optimized when we have a
+    // Z damage estimate instead of INT_MAX
+    bool getClipDamageToBounds() const {
+        return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty());
+    }
+
 private:
 
     // Rendering properties
@@ -481,14 +559,13 @@
         float mPivotX, mPivotY;
         int mLeft, mTop, mRight, mBottom;
         int mWidth, mHeight;
-        int mScrollX, mScrollY;
         bool mPivotExplicitlySet;
         bool mMatrixOrPivotDirty;
-        bool mCaching;
     } mPrimitiveFields;
 
     SkMatrix* mStaticMatrix;
     SkMatrix* mAnimationMatrix;
+    LayerProperties mLayerProperties;
 
     /**
      * These fields are all generated from other properties and are not set directly.
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 41cc9d2..ef3d0d7 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -39,6 +39,7 @@
 
 TessellationCache::Description::Description()
         : type(kNone)
+        , aa(false)
         , cap(SkPaint::kDefault_Cap)
         , style(SkPaint::kFill_Style)
         , strokeWidth(1.0f) {
@@ -47,6 +48,7 @@
 
 TessellationCache::Description::Description(Type type)
         : type(type)
+        , aa(false)
         , cap(SkPaint::kDefault_Cap)
         , style(SkPaint::kFill_Style)
         , strokeWidth(1.0f) {
@@ -55,6 +57,7 @@
 
 TessellationCache::Description::Description(Type type, const SkPaint* paint)
         : type(type)
+        , aa(paint->isAntiAlias())
         , cap(paint->getStrokeCap())
         , style(paint->getStyle())
         , strokeWidth(paint->getStrokeWidth()) {
@@ -63,6 +66,7 @@
 
 hash_t TessellationCache::Description::hash() const {
     uint32_t hash = JenkinsHashMix(0, type);
+    hash = JenkinsHashMix(hash, aa);
     hash = JenkinsHashMix(hash, cap);
     hash = JenkinsHashMix(hash, style);
     hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
@@ -165,12 +169,12 @@
     ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
             const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
             const Vector3& lightCenter, float lightRadius)
-        : drawTransform(drawTransform)
+        : drawTransform(*drawTransform)
         , localClip(localClip)
         , opaque(opaque)
-        , casterPerimeter(casterPerimeter)
-        , transformXY(transformXY)
-        , transformZ(transformZ)
+        , casterPerimeter(*casterPerimeter)
+        , transformXY(*transformXY)
+        , transformZ(*transformZ)
         , lightCenter(lightCenter)
         , lightRadius(lightRadius) {
     }
@@ -182,14 +186,19 @@
         delete bufferPair;
     }
 
-    // Note - only the localClip is deep copied, since other pointers point at Allocator controlled
-    // objects, which are safe for the entire frame
-    const Matrix4* drawTransform;
+    /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
+     * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
+     * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
+     *
+     * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
+     * before tearning down single-frame LinearAllocators.
+     */
+    const Matrix4 drawTransform;
     const Rect localClip;
     bool opaque;
-    const SkPath* casterPerimeter;
-    const Matrix4* transformXY;
-    const Matrix4* transformZ;
+    const SkPath casterPerimeter;
+    const Matrix4 transformXY;
+    const Matrix4 transformZ;
     const Vector3 lightCenter;
     const float lightRadius;
 };
@@ -281,8 +290,8 @@
 
         VertexBuffer* ambientBuffer = new VertexBuffer;
         VertexBuffer* spotBuffer = new VertexBuffer;
-        tessellateShadows(t->drawTransform, &t->localClip, t->opaque, t->casterPerimeter,
-                t->transformXY, t->transformZ, t->lightCenter, t->lightRadius,
+        tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
+                &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
                 *ambientBuffer, *spotBuffer);
 
         t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index 8f37230..d4ff943 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -55,6 +55,7 @@
         };
 
         Type type;
+        bool aa;
         SkPaint::Cap cap;
         SkPaint::Style style;
         float strokeWidth;
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 60b4b96..1001cae0 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -288,19 +288,19 @@
     switch (bitmap->config()) {
     case SkBitmap::kA8_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(),
+        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
                 texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
         texture->blend = true;
         break;
     case SkBitmap::kRGB_565_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
-        uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(),
+        uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
                 texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
         texture->blend = false;
         break;
     case SkBitmap::kARGB_8888_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
-        uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(),
+        uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
                 texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
         // Do this after calling getPixels() to make sure Skia's deferred
         // decoding happened
@@ -340,27 +340,49 @@
     SkCanvas canvas(rgbaBitmap);
     canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
 
-    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height,
-            GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
+    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
+            width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
 }
 
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride,
+void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
         GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
-    // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
-    //       if the stride doesn't match the width
     const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
-    if (useStride) {
-        glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
-    }
+    if ((stride == width) || useStride) {
+        if (useStride) {
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+        }
 
-    if (resize) {
-        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+        if (resize) {
+            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+        }
+
+        if (useStride) {
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+        }
     } else {
-        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
-    }
+        //  With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+        //  if the stride doesn't match the width
 
-    if (useStride) {
-        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+        GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+        if (!temp) return;
+
+        uint8_t * pDst = (uint8_t *)temp;
+        uint8_t * pSrc = (uint8_t *)data;
+        for (GLsizei i = 0; i < height; i++) {
+            memcpy(pDst, pSrc, width * bpp);
+            pDst += width * bpp;
+            pSrc += stride * bpp;
+        }
+
+        if (resize) {
+            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
+        }
+
+        free(temp);
     }
 }
 
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index e5b5c1a..61db5b0 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -142,7 +142,7 @@
     void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate = false);
 
     void uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height);
-    void uploadToTexture(bool resize, GLenum format, GLsizei stride,
+    void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
             GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
 
     void init();
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 2096f98..0fc0cef 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -18,6 +18,7 @@
 
 #include <utils/Timers.h>
 
+#include "DamageAccumulator.h"
 #include "utils/Macros.h"
 
 namespace android {
@@ -25,7 +26,7 @@
 
 class BaseRenderNodeAnimator;
 class AnimationListener;
-class DamageAccumulator;
+class OpenGLRenderer;
 
 class AnimationHook {
 public:
@@ -62,7 +63,8 @@
         , frameTimeMs(0)
         , animationHook(NULL)
         , prepareTextures(mode == MODE_FULL)
-        , damageAccumulator(0)
+        , damageAccumulator(NullDamageAccumulator::instance())
+        , renderer(0)
     {}
 
     const TraversalMode mode;
@@ -71,7 +73,11 @@
     // TODO: Remove this? Currently this is used to signal to stop preparing
     // textures if we run out of cache space.
     bool prepareTextures;
-    DamageAccumulator* damageAccumulator;
+    // Must not be null
+    IDamageAccumulator* damageAccumulator;
+    // The renderer that will be drawing the next frame. Use this to push any
+    // layer updates or similar. May be NULL.
+    OpenGLRenderer* renderer;
 
     struct Out {
         Out()
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8a5c857..dc1951b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -440,6 +440,7 @@
 
     info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
     info.damageAccumulator = &mDamageAccumulator;
+    info.renderer = mCanvas;
     mRootRenderNode->prepareTree(info);
 
     int runningBehind = 0;
@@ -536,9 +537,12 @@
         requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
-    (*functor)(mode, NULL);
 
     if (mCanvas) {
+        mCanvas->interrupt();
+    }
+    (*functor)(mode, NULL);
+    if (mCanvas) {
         mCanvas->resume();
     }
 }
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index bdfdd21..797566f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,9 +130,6 @@
         mContext->processLayerUpdate(mLayers[i].get(), info);
     }
     mLayers.clear();
-    if (info.out.hasAnimations) {
-        // TODO: Uh... crap?
-    }
     mContext->prepareTree(info);
 
     if (info.out.hasAnimations) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ded10a1..4988f19 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -47,7 +47,7 @@
 
 #define SETUP_TASK(method) \
     LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
-        "METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
+        "METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \
                 METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
     MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
     ARGS(method) *args = (ARGS(method) *) task->payload()
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c3d5d94..2f1e11e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -50,12 +50,6 @@
  */
 public class AudioManager {
 
-    // If we should use the new sessions APIs.
-    private final static boolean USE_SESSIONS = true;
-    // If we should use the legacy APIs. If both are true information will be
-    // duplicated through both paths. Currently this flag isn't used.
-    private final static boolean USE_LEGACY = true;
-
     private final Context mContext;
     private long mVolumeKeyUpTime;
     private final boolean mUseMasterVolume;
@@ -483,17 +477,8 @@
      *     or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
      */
     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        if (USE_SESSIONS) {
-            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-            helper.sendMediaButtonEvent(keyEvent, false);
-        } else {
-            IAudioService service = getService();
-            try {
-                service.dispatchMediaKeyEvent(keyEvent);
-            } catch (RemoteException e) {
-                Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
-            }
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        helper.sendMediaButtonEvent(keyEvent, false);
     }
 
     /**
@@ -644,12 +629,8 @@
             if (mUseMasterVolume) {
                 service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
             } else {
-                if (USE_SESSIONS) {
-                    MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-                    helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
-                } else {
-                    service.adjustVolume(direction, flags, mContext.getOpPackageName());
-                }
+                MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+                helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustVolume", e);
@@ -679,13 +660,8 @@
             if (mUseMasterVolume) {
                 service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
             } else {
-                if (USE_SESSIONS) {
-                    MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-                    helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
-                } else {
-                    service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
-                            mContext.getOpPackageName());
-                }
+                MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+                helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
@@ -1425,7 +1401,12 @@
      *           <var>false</var> to turn mute off
      */
     public void setMicrophoneMute(boolean on){
-        AudioSystem.muteMicrophone(on);
+        IAudioService service = getService();
+        try {
+            service.setMicrophoneMute(on, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setMicrophoneMute", e);
+        }
     }
 
     /**
@@ -1653,6 +1634,25 @@
         }
     }
 
+
+    /**
+     * Return a new audio session identifier not associated with any player or effect.
+     * It can for instance be used to create one of the {@link android.media.audiofx.AudioEffect}
+     * objects.
+     * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
+     *   system failed to allocate a new session.
+     */
+    public int allocateAudioSessionId() {
+        int session = AudioSystem.newAudioSessionId();
+        if (session > 0) {
+            return session;
+        } else {
+            Log.e(TAG, "Failure to allocate a new audio session ID");
+            return ERROR;
+        }
+    }
+
+
     /*
      * Sets a generic audio configuration parameter. The use of these parameters
      * are platform dependant, see libaudio
@@ -2191,16 +2191,15 @@
         }
         IAudioService service = getService();
         try {
-            // pi != null
+            // pi != null, this is currently still needed to support across
+            // reboot launching of the last app.
             service.registerMediaButtonIntent(pi, eventReceiver,
                     eventReceiver == null ? mToken : null);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
         }
-        if (USE_SESSIONS) {
-            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-            helper.addMediaButtonListener(pi, mContext);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        helper.addMediaButtonListener(pi, mContext);
     }
 
     /**
@@ -2274,10 +2273,8 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
         }
-        if (USE_SESSIONS) {
-            MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-            helper.removeMediaButtonListener(pi);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        helper.removeMediaButtonListener(pi);
     }
 
     /**
@@ -2291,20 +2288,7 @@
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
-        IAudioService service = getService();
-        try {
-            int rcseId = service.registerRemoteControlClient(
-                    rcClient.getRcMediaIntent(),       /* mediaIntent   */
-                    rcClient.getIRemoteControlClient(),/* rcClient      */
-                    // used to match media button event receiver and audio focus
-                    mContext.getPackageName());        /* packageName   */
-            rcClient.setRcseId(rcseId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
-        }
-        if (USE_SESSIONS) {
-            rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
-        }
+        rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
     }
 
     /**
@@ -2317,16 +2301,7 @@
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
-        IAudioService service = getService();
-        try {
-            service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent   */
-                    rcClient.getIRemoteControlClient());                       /* rcClient      */
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
-        }
-        if (USE_SESSIONS) {
-            rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
-        }
+        rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
     }
 
     /**
@@ -2344,20 +2319,8 @@
         if (rctlr == null) {
             return false;
         }
-        IAudioService service = getService();
-        final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener();
-        final ComponentName listenerComponent = new ComponentName(mContext, l.getClass());
-        try {
-            int[] artworkDimensions = rctlr.getArtworkSize();
-            boolean reg = service.registerRemoteController(rctlr.getRcDisplay(),
-                    artworkDimensions[0]/*w*/, artworkDimensions[1]/*h*/,
-                    listenerComponent);
-            rctlr.setIsRegistered(reg);
-            return reg;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerRemoteController " + e);
-            return false;
-        }
+        rctlr.startListeningToSessions();
+        return true;
     }
 
     /**
@@ -2369,13 +2332,7 @@
         if (rctlr == null) {
             return;
         }
-        IAudioService service = getService();
-        try {
-            service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
-            rctlr.setIsRegistered(false);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
-        }
+        rctlr.stopListeningToSessions();
     }
 
     /**
@@ -2998,7 +2955,8 @@
     /** @hide
      */
     public static final int SUCCESS = AudioSystem.SUCCESS;
-    /** @hide
+    /**
+     * A default error code.
      */
     public static final int ERROR = AudioSystem.ERROR;
     /** @hide
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2f782cc..72f4a58 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -108,8 +108,7 @@
     /** Debug volumes */
     protected static final boolean DEBUG_VOL = false;
 
-    /** Reroute calls to media session apis */
-    private static final boolean USE_SESSIONS = true;
+    /** debug calls to media session apis */
     private static final boolean DEBUG_SESSIONS = true;
 
     /** Allow volume changes to set ringer mode to silent? */
@@ -1437,6 +1436,16 @@
         }
     }
 
+    /** @see AudioManager#setMicrophoneMute(boolean) */
+    public void setMicrophoneMute(boolean on, String callingPackage) {
+        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
+                callingPackage) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
+        AudioSystem.muteMicrophone(on);
+    }
+
     /** @see AudioManager#getRingerMode() */
     public int getRingerMode() {
         synchronized(mSettingsLock) {
@@ -4474,27 +4483,19 @@
     }
 
     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        if (USE_SESSIONS) {
-            if (DEBUG_SESSIONS) {
-                int pid = getCallingPid();
-                Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
-            }
-            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
-        } else {
-            mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+        if (DEBUG_SESSIONS) {
+            int pid = getCallingPid();
+            Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
         }
+        MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
     }
 
     public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
-        if (USE_SESSIONS) {
-            if (DEBUG_SESSIONS) {
-                int pid = getCallingPid();
-                Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
-            }
-            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
-        } else {
-            mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+        if (DEBUG_SESSIONS) {
+            int pid = getCallingPid();
+            Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
         }
+        MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
     }
 
     //==========================================================================================
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index c8d64ce..9fbcd18 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -130,6 +130,11 @@
     public static native boolean isSourceActive(int source);
 
     /*
+     * Returns a new unused audio session ID
+     */
+    public static native int newAudioSessionId();
+
+    /*
      * Sets a group generic audio configuration parameters. The use of these parameters
      * are platform dependent, see libaudio
      *
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 511111c..f9e49c1 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -90,9 +90,14 @@
      */
     public static final int QUALITY_QVGA = 7;
 
+    /**
+     * Quality level corresponding to the 2160p (3840x2160) resolution.
+     */
+    public static final int QUALITY_2160P = 8;
+
     // Start and end of quality list
     private static final int QUALITY_LIST_START = QUALITY_LOW;
-    private static final int QUALITY_LIST_END = QUALITY_QVGA;
+    private static final int QUALITY_LIST_END = QUALITY_2160P;
 
     /**
      * Time lapse quality level corresponding to the lowest available resolution.
@@ -134,9 +139,14 @@
      */
     public static final int QUALITY_TIME_LAPSE_QVGA = 1007;
 
+    /**
+     * Time lapse quality level corresponding to the 2160p (3840 x 2160) resolution.
+     */
+    public static final int QUALITY_TIME_LAPSE_2160P = 1008;
+
     // Start and end of timelapse quality list
     private static final int QUALITY_TIME_LAPSE_LIST_START = QUALITY_TIME_LAPSE_LOW;
-    private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_QVGA;
+    private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2160P;
 
     /**
      * Default recording duration in seconds before the session is terminated.
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
new file mode 100644
index 0000000..ec33c5c
--- /dev/null
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -0,0 +1,1464 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.CharacterStyle;
+import android.text.style.StyleSpan;
+import android.text.style.UnderlineSpan;
+import android.text.style.UpdateAppearance;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Vector;
+
+/** @hide */
+public class ClosedCaptionRenderer extends SubtitleController.Renderer {
+    private final Context mContext;
+    private ClosedCaptionWidget mRenderingWidget;
+
+    public ClosedCaptionRenderer(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public boolean supports(MediaFormat format) {
+        if (format.containsKey(MediaFormat.KEY_MIME)) {
+            return format.getString(MediaFormat.KEY_MIME).equals(
+                    MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608);
+        }
+        return false;
+    }
+
+    @Override
+    public SubtitleTrack createTrack(MediaFormat format) {
+        if (mRenderingWidget == null) {
+            mRenderingWidget = new ClosedCaptionWidget(mContext);
+        }
+        return new ClosedCaptionTrack(mRenderingWidget, format);
+    }
+}
+
+/** @hide */
+class ClosedCaptionTrack extends SubtitleTrack {
+    private final ClosedCaptionWidget mRenderingWidget;
+    private final CCParser mCCParser;
+
+    ClosedCaptionTrack(ClosedCaptionWidget renderingWidget, MediaFormat format) {
+        super(format);
+
+        mRenderingWidget = renderingWidget;
+        mCCParser = new CCParser(renderingWidget);
+    }
+
+    @Override
+    public void onData(byte[] data, boolean eos, long runID) {
+        mCCParser.parse(data);
+    }
+
+    @Override
+    public RenderingWidget getRenderingWidget() {
+        return mRenderingWidget;
+    }
+
+    @Override
+    public void updateView(Vector<Cue> activeCues) {
+        // Overriding with NO-OP, CC rendering by-passes this
+    }
+}
+
+/**
+ * @hide
+ *
+ * CCParser processes CEA-608 closed caption data.
+ *
+ * It calls back into OnDisplayChangedListener upon
+ * display change with styled text for rendering.
+ *
+ */
+class CCParser {
+    public static final int MAX_ROWS = 15;
+    public static final int MAX_COLS = 32;
+
+    private static final String TAG = "CCParser";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static final int INVALID = -1;
+
+    // EIA-CEA-608: Table 70 - Control Codes
+    private static final int RCL = 0x20;
+    private static final int BS  = 0x21;
+    private static final int AOF = 0x22;
+    private static final int AON = 0x23;
+    private static final int DER = 0x24;
+    private static final int RU2 = 0x25;
+    private static final int RU3 = 0x26;
+    private static final int RU4 = 0x27;
+    private static final int FON = 0x28;
+    private static final int RDC = 0x29;
+    private static final int TR  = 0x2a;
+    private static final int RTD = 0x2b;
+    private static final int EDM = 0x2c;
+    private static final int CR  = 0x2d;
+    private static final int ENM = 0x2e;
+    private static final int EOC = 0x2f;
+
+    // Transparent Space
+    private static final char TS = '\u00A0';
+
+    // Captioning Modes
+    private static final int MODE_UNKNOWN = 0;
+    private static final int MODE_PAINT_ON = 1;
+    private static final int MODE_ROLL_UP = 2;
+    private static final int MODE_POP_ON = 3;
+    private static final int MODE_TEXT = 4;
+
+    private final DisplayListener mListener;
+
+    private int mMode = MODE_PAINT_ON;
+    private int mRollUpSize = 4;
+
+    private CCMemory mDisplay = new CCMemory();
+    private CCMemory mNonDisplay = new CCMemory();
+    private CCMemory mTextMem = new CCMemory();
+
+    CCParser(DisplayListener listener) {
+        mListener = listener;
+    }
+
+    void parse(byte[] data) {
+        CCData[] ccData = CCData.fromByteArray(data);
+
+        for (int i = 0; i < ccData.length; i++) {
+            if (DEBUG) {
+                Log.d(TAG, ccData[i].toString());
+            }
+
+            if (handleCtrlCode(ccData[i])
+                    || handleTabOffsets(ccData[i])
+                    || handlePACCode(ccData[i])
+                    || handleMidRowCode(ccData[i])) {
+                continue;
+            }
+
+            handleDisplayableChars(ccData[i]);
+        }
+    }
+
+    interface DisplayListener {
+        public void onDisplayChanged(SpannableStringBuilder[] styledTexts);
+        public CaptionStyle getCaptionStyle();
+    }
+
+    private CCMemory getMemory() {
+        // get the CC memory to operate on for current mode
+        switch (mMode) {
+        case MODE_POP_ON:
+            return mNonDisplay;
+        case MODE_TEXT:
+            // TODO(chz): support only caption mode for now,
+            // in text mode, dump everything to text mem.
+            return mTextMem;
+        case MODE_PAINT_ON:
+        case MODE_ROLL_UP:
+            return mDisplay;
+        default:
+            Log.w(TAG, "unrecoginized mode: " + mMode);
+        }
+        return mDisplay;
+    }
+
+    private boolean handleDisplayableChars(CCData ccData) {
+        if (!ccData.isDisplayableChar()) {
+            return false;
+        }
+
+        // Extended char includes 1 automatic backspace
+        if (ccData.isExtendedChar()) {
+            getMemory().bs();
+        }
+
+        getMemory().writeText(ccData.getDisplayText());
+
+        if (mMode == MODE_PAINT_ON || mMode == MODE_ROLL_UP) {
+            updateDisplay();
+        }
+
+        return true;
+    }
+
+    private boolean handleMidRowCode(CCData ccData) {
+        StyleCode m = ccData.getMidRow();
+        if (m != null) {
+            getMemory().writeMidRowCode(m);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean handlePACCode(CCData ccData) {
+        PAC pac = ccData.getPAC();
+
+        if (pac != null) {
+            if (mMode == MODE_ROLL_UP) {
+                getMemory().moveBaselineTo(pac.getRow(), mRollUpSize);
+            }
+            getMemory().writePAC(pac);
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean handleTabOffsets(CCData ccData) {
+        int tabs = ccData.getTabOffset();
+
+        if (tabs > 0) {
+            getMemory().tab(tabs);
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean handleCtrlCode(CCData ccData) {
+        int ctrlCode = ccData.getCtrlCode();
+        switch(ctrlCode) {
+        case RCL:
+            // select pop-on style
+            mMode = MODE_POP_ON;
+            break;
+        case BS:
+            getMemory().bs();
+            break;
+        case DER:
+            getMemory().der();
+            break;
+        case RU2:
+        case RU3:
+        case RU4:
+            mRollUpSize = (ctrlCode - 0x23);
+            // erase memory if currently in other style
+            if (mMode != MODE_ROLL_UP) {
+                mDisplay.erase();
+                mNonDisplay.erase();
+            }
+            // select roll-up style
+            mMode = MODE_ROLL_UP;
+            break;
+        case FON:
+            Log.i(TAG, "Flash On");
+            break;
+        case RDC:
+            // select paint-on style
+            mMode = MODE_PAINT_ON;
+            break;
+        case TR:
+            mMode = MODE_TEXT;
+            mTextMem.erase();
+            break;
+        case RTD:
+            mMode = MODE_TEXT;
+            break;
+        case EDM:
+            // erase display memory
+            mDisplay.erase();
+            updateDisplay();
+            break;
+        case CR:
+            if (mMode == MODE_ROLL_UP) {
+                getMemory().rollUp(mRollUpSize);
+            } else {
+                getMemory().cr();
+            }
+            if (mMode == MODE_ROLL_UP) {
+                updateDisplay();
+            }
+            break;
+        case ENM:
+            // erase non-display memory
+            mNonDisplay.erase();
+            break;
+        case EOC:
+            // swap display/non-display memory
+            swapMemory();
+            // switch to pop-on style
+            mMode = MODE_POP_ON;
+            updateDisplay();
+            break;
+        case INVALID:
+        default:
+            // not handled
+            return false;
+        }
+
+        // handled
+        return true;
+    }
+
+    private void updateDisplay() {
+        if (mListener != null) {
+            CaptionStyle captionStyle = mListener.getCaptionStyle();
+            mListener.onDisplayChanged(mDisplay.getStyledText(captionStyle));
+        }
+    }
+
+    private void swapMemory() {
+        CCMemory temp = mDisplay;
+        mDisplay = mNonDisplay;
+        mNonDisplay = temp;
+    }
+
+    private static class StyleCode {
+        static final int COLOR_WHITE = 0;
+        static final int COLOR_GREEN = 1;
+        static final int COLOR_BLUE = 2;
+        static final int COLOR_CYAN = 3;
+        static final int COLOR_RED = 4;
+        static final int COLOR_YELLOW = 5;
+        static final int COLOR_MAGENTA = 6;
+        static final int COLOR_INVALID = 7;
+
+        static final int STYLE_ITALICS   = 0x00000001;
+        static final int STYLE_UNDERLINE = 0x00000002;
+
+        static final String[] mColorMap = {
+            "WHITE", "GREEN", "BLUE", "CYAN", "RED", "YELLOW", "MAGENTA", "INVALID"
+        };
+
+        final int mStyle;
+        final int mColor;
+
+        static StyleCode fromByte(byte data2) {
+            int style = 0;
+            int color = (data2 >> 1) & 0x7;
+
+            if ((data2 & 0x1) != 0) {
+                style |= STYLE_UNDERLINE;
+            }
+
+            if (color == COLOR_INVALID) {
+                // WHITE ITALICS
+                color = COLOR_WHITE;
+                style |= STYLE_ITALICS;
+            }
+
+            return new StyleCode(style, color);
+        }
+
+        StyleCode(int style, int color) {
+            mStyle = style;
+            mColor = color;
+        }
+
+        boolean isItalics() {
+            return (mStyle & STYLE_ITALICS) != 0;
+        }
+
+        boolean isUnderline() {
+            return (mStyle & STYLE_UNDERLINE) != 0;
+        }
+
+        int getColor() {
+            return mColor;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder str = new StringBuilder();
+            str.append("{");
+            str.append(mColorMap[mColor]);
+            if ((mStyle & STYLE_ITALICS) != 0) {
+                str.append(", ITALICS");
+            }
+            if ((mStyle & STYLE_UNDERLINE) != 0) {
+                str.append(", UNDERLINE");
+            }
+            str.append("}");
+
+            return str.toString();
+        }
+    }
+
+    private static class PAC extends StyleCode {
+        final int mRow;
+        final int mCol;
+
+        static PAC fromBytes(byte data1, byte data2) {
+            int[] rowTable = {11, 1, 3, 12, 14, 5, 7, 9};
+            int row = rowTable[data1 & 0x07] + ((data2 & 0x20) >> 5);
+            int style = 0;
+            if ((data2 & 1) != 0) {
+                style |= STYLE_UNDERLINE;
+            }
+            if ((data2 & 0x10) != 0) {
+                // indent code
+                int indent = (data2 >> 1) & 0x7;
+                return new PAC(row, indent * 4, style, COLOR_WHITE);
+            } else {
+                // style code
+                int color = (data2 >> 1) & 0x7;
+
+                if (color == COLOR_INVALID) {
+                    // WHITE ITALICS
+                    color = COLOR_WHITE;
+                    style |= STYLE_ITALICS;
+                }
+                return new PAC(row, -1, style, color);
+            }
+        }
+
+        PAC(int row, int col, int style, int color) {
+            super(style, color);
+            mRow = row;
+            mCol = col;
+        }
+
+        boolean isIndentPAC() {
+            return (mCol >= 0);
+        }
+
+        int getRow() {
+            return mRow;
+        }
+
+        int getCol() {
+            return mCol;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{%d, %d}, %s",
+                    mRow, mCol, super.toString());
+        }
+    }
+
+    /* CCLineBuilder keeps track of displayable chars, as well as
+     * MidRow styles and PACs, for a single line of CC memory.
+     *
+     * It generates styled text via getStyledText() method.
+     */
+    private static class CCLineBuilder {
+        private final StringBuilder mDisplayChars;
+        private final StyleCode[] mMidRowStyles;
+        private final StyleCode[] mPACStyles;
+
+        CCLineBuilder(String str) {
+            mDisplayChars = new StringBuilder(str);
+            mMidRowStyles = new StyleCode[mDisplayChars.length()];
+            mPACStyles = new StyleCode[mDisplayChars.length()];
+        }
+
+        void setCharAt(int index, char ch) {
+            mDisplayChars.setCharAt(index, ch);
+            mMidRowStyles[index] = null;
+        }
+
+        void setMidRowAt(int index, StyleCode m) {
+            mDisplayChars.setCharAt(index, ' ');
+            mMidRowStyles[index] = m;
+        }
+
+        void setPACAt(int index, PAC pac) {
+            mPACStyles[index] = pac;
+        }
+
+        char charAt(int index) {
+            return mDisplayChars.charAt(index);
+        }
+
+        int length() {
+            return mDisplayChars.length();
+        }
+
+        void applyStyleSpan(
+                SpannableStringBuilder styledText,
+                StyleCode s, int start, int end) {
+            if (s.isItalics()) {
+                styledText.setSpan(
+                        new StyleSpan(android.graphics.Typeface.ITALIC),
+                        start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            }
+            if (s.isUnderline()) {
+                styledText.setSpan(
+                        new UnderlineSpan(),
+                        start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            }
+        }
+
+        SpannableStringBuilder getStyledText(CaptionStyle captionStyle) {
+            SpannableStringBuilder styledText = new SpannableStringBuilder(mDisplayChars);
+            int start = -1, next = 0;
+            int styleStart = -1;
+            StyleCode curStyle = null;
+            while (next < mDisplayChars.length()) {
+                StyleCode newStyle = null;
+                if (mMidRowStyles[next] != null) {
+                    // apply mid-row style change
+                    newStyle = mMidRowStyles[next];
+                } else if (mPACStyles[next] != null
+                    && (styleStart < 0 || start < 0)) {
+                    // apply PAC style change, only if:
+                    // 1. no style set, or
+                    // 2. style set, but prev char is none-displayable
+                    newStyle = mPACStyles[next];
+                }
+                if (newStyle != null) {
+                    curStyle = newStyle;
+                    if (styleStart >= 0 && start >= 0) {
+                        applyStyleSpan(styledText, newStyle, styleStart, next);
+                    }
+                    styleStart = next;
+                }
+
+                if (mDisplayChars.charAt(next) != TS) {
+                    if (start < 0) {
+                        start = next;
+                    }
+                } else if (start >= 0) {
+                    int expandedStart = mDisplayChars.charAt(start) == ' ' ? start : start - 1;
+                    int expandedEnd = mDisplayChars.charAt(next - 1) == ' ' ? next : next + 1;
+                    styledText.setSpan(
+                            new MutableBackgroundColorSpan(captionStyle.backgroundColor),
+                            expandedStart, expandedEnd,
+                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    if (styleStart >= 0) {
+                        applyStyleSpan(styledText, curStyle, styleStart, expandedEnd);
+                    }
+                    start = -1;
+                }
+                next++;
+            }
+
+            return styledText;
+        }
+    }
+
+    /*
+     * CCMemory models a console-style display.
+     */
+    private static class CCMemory {
+        private final String mBlankLine;
+        private final CCLineBuilder[] mLines = new CCLineBuilder[MAX_ROWS + 2];
+        private int mRow;
+        private int mCol;
+
+        CCMemory() {
+            char[] blank = new char[MAX_COLS + 2];
+            Arrays.fill(blank, TS);
+            mBlankLine = new String(blank);
+        }
+
+        void erase() {
+            // erase all lines
+            for (int i = 0; i < mLines.length; i++) {
+                mLines[i] = null;
+            }
+            mRow = MAX_ROWS;
+            mCol = 1;
+        }
+
+        void der() {
+            if (mLines[mRow] != null) {
+                for (int i = 0; i < mCol; i++) {
+                    if (mLines[mRow].charAt(i) != TS) {
+                        for (int j = mCol; j < mLines[mRow].length(); j++) {
+                            mLines[j].setCharAt(j, TS);
+                        }
+                        return;
+                    }
+                }
+                mLines[mRow] = null;
+            }
+        }
+
+        void tab(int tabs) {
+            moveCursorByCol(tabs);
+        }
+
+        void bs() {
+            moveCursorByCol(-1);
+            if (mLines[mRow] != null) {
+                mLines[mRow].setCharAt(mCol, TS);
+                if (mCol == MAX_COLS - 1) {
+                    // Spec recommendation:
+                    // if cursor was at col 32, move cursor
+                    // back to col 31 and erase both col 31&32
+                    mLines[mRow].setCharAt(MAX_COLS, TS);
+                }
+            }
+        }
+
+        void cr() {
+            moveCursorTo(mRow + 1, 1);
+        }
+
+        void rollUp(int windowSize) {
+            int i;
+            for (i = 0; i <= mRow - windowSize; i++) {
+                mLines[i] = null;
+            }
+            int startRow = mRow - windowSize + 1;
+            if (startRow < 1) {
+                startRow = 1;
+            }
+            for (i = startRow; i < mRow; i++) {
+                mLines[i] = mLines[i + 1];
+            }
+            for (i = mRow; i < mLines.length; i++) {
+                // clear base row
+                mLines[i] = null;
+            }
+            // default to col 1, in case PAC is not sent
+            mCol = 1;
+        }
+
+        void writeText(String text) {
+            for (int i = 0; i < text.length(); i++) {
+                getLineBuffer(mRow).setCharAt(mCol, text.charAt(i));
+                moveCursorByCol(1);
+            }
+        }
+
+        void writeMidRowCode(StyleCode m) {
+            getLineBuffer(mRow).setMidRowAt(mCol, m);
+            moveCursorByCol(1);
+        }
+
+        void writePAC(PAC pac) {
+            if (pac.isIndentPAC()) {
+                moveCursorTo(pac.getRow(), pac.getCol());
+            } else {
+                moveCursorToRow(pac.getRow());
+            }
+            getLineBuffer(mRow).setPACAt(mCol, pac);
+        }
+
+        SpannableStringBuilder[] getStyledText(CaptionStyle captionStyle) {
+            ArrayList<SpannableStringBuilder> rows =
+                    new ArrayList<SpannableStringBuilder>(MAX_ROWS);
+            for (int i = 1; i <= MAX_ROWS; i++) {
+                rows.add(mLines[i] != null ?
+                        mLines[i].getStyledText(captionStyle) : null);
+            }
+            return rows.toArray(new SpannableStringBuilder[MAX_ROWS]);
+        }
+
+        private static int clamp(int x, int min, int max) {
+            return x < min ? min : (x > max ? max : x);
+        }
+
+        private void moveCursorTo(int row, int col) {
+            mRow = clamp(row, 1, MAX_ROWS);
+            mCol = clamp(col, 1, MAX_COLS);
+        }
+
+        private void moveCursorToRow(int row) {
+            mRow = clamp(row, 1, MAX_ROWS);
+        }
+
+        private void moveCursorByCol(int col) {
+            mCol = clamp(mCol + col, 1, MAX_COLS);
+        }
+
+        private void moveBaselineTo(int baseRow, int windowSize) {
+            if (mRow == baseRow) {
+                return;
+            }
+            int actualWindowSize = windowSize;
+            if (baseRow < actualWindowSize) {
+                actualWindowSize = baseRow;
+            }
+            if (mRow < actualWindowSize) {
+                actualWindowSize = mRow;
+            }
+
+            int i;
+            if (baseRow < mRow) {
+                // copy from bottom to top row
+                for (i = actualWindowSize - 1; i >= 0; i--) {
+                    mLines[baseRow - i] = mLines[mRow - i];
+                }
+            } else {
+                // copy from top to bottom row
+                for (i = 0; i < actualWindowSize; i++) {
+                    mLines[baseRow - i] = mLines[mRow - i];
+                }
+            }
+            // clear rest of the rows
+            for (i = 0; i <= baseRow - windowSize; i++) {
+                mLines[i] = null;
+            }
+            for (i = baseRow + 1; i < mLines.length; i++) {
+                mLines[i] = null;
+            }
+        }
+
+        private CCLineBuilder getLineBuffer(int row) {
+            if (mLines[row] == null) {
+                mLines[row] = new CCLineBuilder(mBlankLine);
+            }
+            return mLines[row];
+        }
+    }
+
+    /*
+     * CCData parses the raw CC byte pair into displayable chars,
+     * misc control codes, Mid-Row or Preamble Address Codes.
+     */
+    private static class CCData {
+        private final byte mType;
+        private final byte mData1;
+        private final byte mData2;
+
+        private static final String[] mCtrlCodeMap = {
+            "RCL", "BS" , "AOF", "AON",
+            "DER", "RU2", "RU3", "RU4",
+            "FON", "RDC", "TR" , "RTD",
+            "EDM", "CR" , "ENM", "EOC",
+        };
+
+        private static final String[] mSpecialCharMap = {
+            "\u00AE",
+            "\u00B0",
+            "\u00BD",
+            "\u00BF",
+            "\u2122",
+            "\u00A2",
+            "\u00A3",
+            "\u266A", // Eighth note
+            "\u00E0",
+            "\u00A0", // Transparent space
+            "\u00E8",
+            "\u00E2",
+            "\u00EA",
+            "\u00EE",
+            "\u00F4",
+            "\u00FB",
+        };
+
+        private static final String[] mSpanishCharMap = {
+            // Spanish and misc chars
+            "\u00C1", // A
+            "\u00C9", // E
+            "\u00D3", // I
+            "\u00DA", // O
+            "\u00DC", // U
+            "\u00FC", // u
+            "\u2018", // opening single quote
+            "\u00A1", // inverted exclamation mark
+            "*",
+            "'",
+            "\u2014", // em dash
+            "\u00A9", // Copyright
+            "\u2120", // Servicemark
+            "\u2022", // round bullet
+            "\u201C", // opening double quote
+            "\u201D", // closing double quote
+            // French
+            "\u00C0",
+            "\u00C2",
+            "\u00C7",
+            "\u00C8",
+            "\u00CA",
+            "\u00CB",
+            "\u00EB",
+            "\u00CE",
+            "\u00CF",
+            "\u00EF",
+            "\u00D4",
+            "\u00D9",
+            "\u00F9",
+            "\u00DB",
+            "\u00AB",
+            "\u00BB"
+        };
+
+        private static final String[] mProtugueseCharMap = {
+            // Portuguese
+            "\u00C3",
+            "\u00E3",
+            "\u00CD",
+            "\u00CC",
+            "\u00EC",
+            "\u00D2",
+            "\u00F2",
+            "\u00D5",
+            "\u00F5",
+            "{",
+            "}",
+            "\\",
+            "^",
+            "_",
+            "|",
+            "~",
+            // German and misc chars
+            "\u00C4",
+            "\u00E4",
+            "\u00D6",
+            "\u00F6",
+            "\u00DF",
+            "\u00A5",
+            "\u00A4",
+            "\u2502", // vertical bar
+            "\u00C5",
+            "\u00E5",
+            "\u00D8",
+            "\u00F8",
+            "\u250C", // top-left corner
+            "\u2510", // top-right corner
+            "\u2514", // lower-left corner
+            "\u2518", // lower-right corner
+        };
+
+        static CCData[] fromByteArray(byte[] data) {
+            CCData[] ccData = new CCData[data.length / 3];
+
+            for (int i = 0; i < ccData.length; i++) {
+                ccData[i] = new CCData(
+                        data[i * 3],
+                        data[i * 3 + 1],
+                        data[i * 3 + 2]);
+            }
+
+            return ccData;
+        }
+
+        CCData(byte type, byte data1, byte data2) {
+            mType = type;
+            mData1 = data1;
+            mData2 = data2;
+        }
+
+        int getCtrlCode() {
+            if ((mData1 == 0x14 || mData1 == 0x1c)
+                    && mData2 >= 0x20 && mData2 <= 0x2f) {
+                return mData2;
+            }
+            return INVALID;
+        }
+
+        StyleCode getMidRow() {
+            // only support standard Mid-row codes, ignore
+            // optional background/foreground mid-row codes
+            if ((mData1 == 0x11 || mData1 == 0x19)
+                    && mData2 >= 0x20 && mData2 <= 0x2f) {
+                return StyleCode.fromByte(mData2);
+            }
+            return null;
+        }
+
+        PAC getPAC() {
+            if ((mData1 & 0x70) == 0x10
+                    && (mData2 & 0x40) == 0x40
+                    && ((mData1 & 0x07) != 0 || (mData2 & 0x20) == 0)) {
+                return PAC.fromBytes(mData1, mData2);
+            }
+            return null;
+        }
+
+        int getTabOffset() {
+            if ((mData1 == 0x17 || mData1 == 0x1f)
+                    && mData2 >= 0x21 && mData2 <= 0x23) {
+                return mData2 & 0x3;
+            }
+            return 0;
+        }
+
+        boolean isDisplayableChar() {
+            return isBasicChar() || isSpecialChar() || isExtendedChar();
+        }
+
+        String getDisplayText() {
+            String str = getBasicChars();
+
+            if (str == null) {
+                str =  getSpecialChar();
+
+                if (str == null) {
+                    str = getExtendedChar();
+                }
+            }
+
+            return str;
+        }
+
+        private String ctrlCodeToString(int ctrlCode) {
+            return mCtrlCodeMap[ctrlCode - 0x20];
+        }
+
+        private boolean isBasicChar() {
+            return mData1 >= 0x20 && mData1 <= 0x7f;
+        }
+
+        private boolean isSpecialChar() {
+            return ((mData1 == 0x11 || mData1 == 0x19)
+                    && mData2 >= 0x30 && mData2 <= 0x3f);
+        }
+
+        private boolean isExtendedChar() {
+            return ((mData1 == 0x12 || mData1 == 0x1A
+                    || mData1 == 0x13 || mData1 == 0x1B)
+                    && mData2 >= 0x20 && mData2 <= 0x3f);
+        }
+
+        private char getBasicChar(byte data) {
+            char c;
+            // replace the non-ASCII ones
+            switch (data) {
+                case 0x2A: c = '\u00E1'; break;
+                case 0x5C: c = '\u00E9'; break;
+                case 0x5E: c = '\u00ED'; break;
+                case 0x5F: c = '\u00F3'; break;
+                case 0x60: c = '\u00FA'; break;
+                case 0x7B: c = '\u00E7'; break;
+                case 0x7C: c = '\u00F7'; break;
+                case 0x7D: c = '\u00D1'; break;
+                case 0x7E: c = '\u00F1'; break;
+                case 0x7F: c = '\u2588'; break; // Full block
+                default: c = (char) data; break;
+            }
+            return c;
+        }
+
+        private String getBasicChars() {
+            if (mData1 >= 0x20 && mData1 <= 0x7f) {
+                StringBuilder builder = new StringBuilder(2);
+                builder.append(getBasicChar(mData1));
+                if (mData2 >= 0x20 && mData2 <= 0x7f) {
+                    builder.append(getBasicChar(mData2));
+                }
+                return builder.toString();
+            }
+
+            return null;
+        }
+
+        private String getSpecialChar() {
+            if ((mData1 == 0x11 || mData1 == 0x19)
+                    && mData2 >= 0x30 && mData2 <= 0x3f) {
+                return mSpecialCharMap[mData2 - 0x30];
+            }
+
+            return null;
+        }
+
+        private String getExtendedChar() {
+            if ((mData1 == 0x12 || mData1 == 0x1A)
+                    && mData2 >= 0x20 && mData2 <= 0x3f){
+                // 1 Spanish/French char
+                return mSpanishCharMap[mData2 - 0x20];
+            } else if ((mData1 == 0x13 || mData1 == 0x1B)
+                    && mData2 >= 0x20 && mData2 <= 0x3f){
+                // 1 Portuguese/German/Danish char
+                return mProtugueseCharMap[mData2 - 0x20];
+            }
+
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            String str;
+
+            if (mData1 < 0x10 && mData2 < 0x10) {
+                // Null Pad, ignore
+                return String.format("[%d]Null: %02x %02x", mType, mData1, mData2);
+            }
+
+            int ctrlCode = getCtrlCode();
+            if (ctrlCode != INVALID) {
+                return String.format("[%d]%s", mType, ctrlCodeToString(ctrlCode));
+            }
+
+            int tabOffset = getTabOffset();
+            if (tabOffset > 0) {
+                return String.format("[%d]Tab%d", mType, tabOffset);
+            }
+
+            PAC pac = getPAC();
+            if (pac != null) {
+                return String.format("[%d]PAC: %s", mType, pac.toString());
+            }
+
+            StyleCode m = getMidRow();
+            if (m != null) {
+                return String.format("[%d]Mid-row: %s", mType, m.toString());
+            }
+
+            if (isDisplayableChar()) {
+                return String.format("[%d]Displayable: %s (%02x %02x)",
+                        mType, getDisplayText(), mData1, mData2);
+            }
+
+            return String.format("[%d]Invalid: %02x %02x", mType, mData1, mData2);
+        }
+    }
+}
+
+/**
+ * @hide
+ *
+ * MutableBackgroundColorSpan
+ *
+ * This is a mutable version of BackgroundSpan to facilitate text
+ * rendering with edge styles.
+ *
+ */
+class MutableBackgroundColorSpan extends CharacterStyle
+        implements UpdateAppearance, ParcelableSpan {
+    private int mColor;
+
+    public MutableBackgroundColorSpan(int color) {
+        mColor = color;
+    }
+    public MutableBackgroundColorSpan(Parcel src) {
+        mColor = src.readInt();
+    }
+    public void setBackgroundColor(int color) {
+        mColor = color;
+    }
+    public int getBackgroundColor() {
+        return mColor;
+    }
+    @Override
+    public int getSpanTypeId() {
+        return TextUtils.BACKGROUND_COLOR_SPAN;
+    }
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mColor);
+    }
+    @Override
+    public void updateDrawState(TextPaint ds) {
+        ds.bgColor = mColor;
+    }
+}
+
+/**
+ * Widget capable of rendering CEA-608 closed captions.
+ *
+ * @hide
+ */
+class ClosedCaptionWidget extends ViewGroup implements
+        SubtitleTrack.RenderingWidget,
+        CCParser.DisplayListener {
+    private static final String TAG = "ClosedCaptionWidget";
+
+    private static final Rect mTextBounds = new Rect();
+    private static final String mDummyText = "1234567890123456789012345678901234";
+    private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT;
+
+    /** Captioning manager, used to obtain and track caption properties. */
+    private final CaptioningManager mManager;
+
+    /** Callback for rendering changes. */
+    private OnChangedListener mListener;
+
+    /** Current caption style. */
+    private CaptionStyle mCaptionStyle;
+
+    /* Closed caption layout. */
+    private CCLayout mClosedCaptionLayout;
+
+    /** Whether a caption style change listener is registered. */
+    private boolean mHasChangeListener;
+
+    public ClosedCaptionWidget(Context context) {
+        this(context, null);
+    }
+
+    public ClosedCaptionWidget(Context context, AttributeSet attrs) {
+        this(context, null, 0);
+    }
+
+    public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        // Cannot render text over video when layer type is hardware.
+        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+        mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+        mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(mManager.getUserStyle());
+
+        mClosedCaptionLayout = new CCLayout(context);
+        mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+        addView(mClosedCaptionLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+        requestLayout();
+    }
+
+    @Override
+    public void setOnChangedListener(OnChangedListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public void setSize(int width, int height) {
+        final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+        final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+        measure(widthSpec, heightSpec);
+        layout(0, 0, width, height);
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            setVisibility(View.VISIBLE);
+        } else {
+            setVisibility(View.GONE);
+        }
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void onDisplayChanged(SpannableStringBuilder[] styledTexts) {
+        mClosedCaptionLayout.update(styledTexts);
+
+        if (mListener != null) {
+            mListener.onChanged(this);
+        }
+    }
+
+    @Override
+    public CaptionStyle getCaptionStyle() {
+        return mCaptionStyle;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mClosedCaptionLayout.measure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mClosedCaptionLayout.layout(l, t, r, b);
+    }
+
+    /**
+     * Manages whether this renderer is listening for caption style changes.
+     */
+    private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+        @Override
+        public void onUserStyleChanged(CaptionStyle userStyle) {
+            mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(userStyle);
+            mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+        }
+    };
+
+    private void manageChangeListener() {
+        final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+        if (mHasChangeListener != needsListener) {
+            mHasChangeListener = needsListener;
+
+            if (needsListener) {
+                mManager.addCaptioningChangeListener(mCaptioningListener);
+            } else {
+                mManager.removeCaptioningChangeListener(mCaptioningListener);
+            }
+        }
+    }
+
+    private static class CCLineBox extends TextView {
+        private static final float FONT_PADDING_RATIO = 0.75f;
+        private static final float EDGE_OUTLINE_RATIO = 0.1f;
+        private static final float EDGE_SHADOW_RATIO = 0.05f;
+        private float mOutlineWidth;
+        private float mShadowRadius;
+        private float mShadowOffset;
+
+        private int mTextColor = Color.WHITE;
+        private int mBgColor = Color.BLACK;
+        private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
+        private int mEdgeColor = Color.TRANSPARENT;
+
+        CCLineBox(Context context) {
+            super(context);
+            setGravity(Gravity.CENTER);
+            setBackgroundColor(Color.TRANSPARENT);
+            setTextColor(Color.WHITE);
+            setTypeface(Typeface.MONOSPACE);
+            setVisibility(View.INVISIBLE);
+
+            final Resources res = getContext().getResources();
+
+            // get the default (will be updated later during measure)
+            mOutlineWidth = res.getDimensionPixelSize(
+                    com.android.internal.R.dimen.subtitle_outline_width);
+            mShadowRadius = res.getDimensionPixelSize(
+                    com.android.internal.R.dimen.subtitle_shadow_radius);
+            mShadowOffset = res.getDimensionPixelSize(
+                    com.android.internal.R.dimen.subtitle_shadow_offset);
+        }
+
+        void setCaptionStyle(CaptionStyle captionStyle) {
+            mTextColor = captionStyle.foregroundColor;
+            mBgColor = captionStyle.backgroundColor;
+            mEdgeType = captionStyle.edgeType;
+            mEdgeColor = captionStyle.edgeColor;
+
+            setTextColor(mTextColor);
+            if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+                setShadowLayer(mShadowRadius, mShadowOffset, mShadowOffset, mEdgeColor);
+            } else {
+                setShadowLayer(0, 0, 0, 0);
+            }
+            invalidate();
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            float fontSize = MeasureSpec.getSize(heightMeasureSpec)
+                    * FONT_PADDING_RATIO;
+            setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
+
+            mOutlineWidth = EDGE_OUTLINE_RATIO * fontSize + 1.0f;
+            mShadowRadius = EDGE_SHADOW_RATIO * fontSize + 1.0f;;
+            mShadowOffset = mShadowRadius;
+
+            // set font scale in the X direction to match the required width
+            setScaleX(1.0f);
+            getPaint().getTextBounds(mDummyText, 0, mDummyText.length(), mTextBounds);
+            float actualTextWidth = mTextBounds.width();
+            float requiredTextWidth = MeasureSpec.getSize(widthMeasureSpec);
+            setScaleX(requiredTextWidth / actualTextWidth);
+
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        @Override
+        protected void onDraw(Canvas c) {
+            if (mEdgeType == CaptionStyle.EDGE_TYPE_UNSPECIFIED
+                    || mEdgeType == CaptionStyle.EDGE_TYPE_NONE
+                    || mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+                // these edge styles don't require a second pass
+                super.onDraw(c);
+                return;
+            }
+
+            if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+                drawEdgeOutline(c);
+            } else {
+                // Raised or depressed
+                drawEdgeRaisedOrDepressed(c);
+            }
+        }
+
+        private void drawEdgeOutline(Canvas c) {
+            TextPaint textPaint = getPaint();
+
+            Paint.Style previousStyle = textPaint.getStyle();
+            Paint.Join previousJoin = textPaint.getStrokeJoin();
+            float previousWidth = textPaint.getStrokeWidth();
+
+            setTextColor(mEdgeColor);
+            textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+            textPaint.setStrokeJoin(Paint.Join.ROUND);
+            textPaint.setStrokeWidth(mOutlineWidth);
+
+            // Draw outline and background only.
+            super.onDraw(c);
+
+            // Restore original settings.
+            setTextColor(mTextColor);
+            textPaint.setStyle(previousStyle);
+            textPaint.setStrokeJoin(previousJoin);
+            textPaint.setStrokeWidth(previousWidth);
+
+            // Remove the background.
+            setBackgroundSpans(Color.TRANSPARENT);
+            // Draw foreground only.
+            super.onDraw(c);
+            // Restore the background.
+            setBackgroundSpans(mBgColor);
+        }
+
+        private void drawEdgeRaisedOrDepressed(Canvas c) {
+            TextPaint textPaint = getPaint();
+
+            Paint.Style previousStyle = textPaint.getStyle();
+            textPaint.setStyle(Paint.Style.FILL);
+
+            final boolean raised = mEdgeType == CaptionStyle.EDGE_TYPE_RAISED;
+            final int colorUp = raised ? Color.WHITE : mEdgeColor;
+            final int colorDown = raised ? mEdgeColor : Color.WHITE;
+            final float offset = mShadowRadius / 2f;
+
+            // Draw background and text with shadow up
+            setShadowLayer(mShadowRadius, -offset, -offset, colorUp);
+            super.onDraw(c);
+
+            // Remove the background.
+            setBackgroundSpans(Color.TRANSPARENT);
+
+            // Draw text with shadow down
+            setShadowLayer(mShadowRadius, +offset, +offset, colorDown);
+            super.onDraw(c);
+
+            // Restore settings
+            textPaint.setStyle(previousStyle);
+
+            // Restore the background.
+            setBackgroundSpans(mBgColor);
+        }
+
+        private void setBackgroundSpans(int color) {
+            CharSequence text = getText();
+            if (text instanceof Spannable) {
+                Spannable spannable = (Spannable) text;
+                MutableBackgroundColorSpan[] bgSpans = spannable.getSpans(
+                        0, spannable.length(), MutableBackgroundColorSpan.class);
+                for (int i = 0; i < bgSpans.length; i++) {
+                    bgSpans[i].setBackgroundColor(color);
+                }
+            }
+        }
+    }
+
+    private static class CCLayout extends LinearLayout {
+        private static final int MAX_ROWS = CCParser.MAX_ROWS;
+        private static final float SAFE_AREA_RATIO = 0.9f;
+
+        private final CCLineBox[] mLineBoxes = new CCLineBox[MAX_ROWS];
+
+        CCLayout(Context context) {
+            super(context);
+            setGravity(Gravity.START);
+            setOrientation(LinearLayout.VERTICAL);
+            for (int i = 0; i < MAX_ROWS; i++) {
+                mLineBoxes[i] = new CCLineBox(getContext());
+                addView(mLineBoxes[i], LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+            }
+        }
+
+        void setCaptionStyle(CaptionStyle captionStyle) {
+            for (int i = 0; i < MAX_ROWS; i++) {
+                mLineBoxes[i].setCaptionStyle(captionStyle);
+            }
+        }
+
+        void update(SpannableStringBuilder[] textBuffer) {
+            for (int i = 0; i < MAX_ROWS; i++) {
+                if (textBuffer[i] != null) {
+                    mLineBoxes[i].setText(textBuffer[i], TextView.BufferType.SPANNABLE);
+                    mLineBoxes[i].setVisibility(View.VISIBLE);
+                } else {
+                    mLineBoxes[i].setVisibility(View.INVISIBLE);
+                }
+            }
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+            int safeWidth = getMeasuredWidth();
+            int safeHeight = getMeasuredHeight();
+
+            // CEA-608 assumes 4:3 video
+            if (safeWidth * 3 >= safeHeight * 4) {
+                safeWidth = safeHeight * 4 / 3;
+            } else {
+                safeHeight = safeWidth * 3 / 4;
+            }
+            safeWidth *= SAFE_AREA_RATIO;
+            safeHeight *= SAFE_AREA_RATIO;
+
+            int lineHeight = safeHeight / MAX_ROWS;
+            int lineHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                    lineHeight, MeasureSpec.EXACTLY);
+            int lineWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                    safeWidth, MeasureSpec.EXACTLY);
+
+            for (int i = 0; i < MAX_ROWS; i++) {
+                mLineBoxes[i].measure(lineWidthMeasureSpec, lineHeightMeasureSpec);
+            }
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            // safe caption area
+            int viewPortWidth = r - l;
+            int viewPortHeight = b - t;
+            int safeWidth, safeHeight;
+            // CEA-608 assumes 4:3 video
+            if (viewPortWidth * 3 >= viewPortHeight * 4) {
+                safeWidth = viewPortHeight * 4 / 3;
+                safeHeight = viewPortHeight;
+            } else {
+                safeWidth = viewPortWidth;
+                safeHeight = viewPortWidth * 3 / 4;
+            }
+            safeWidth *= SAFE_AREA_RATIO;
+            safeHeight *= SAFE_AREA_RATIO;
+            int left = (viewPortWidth - safeWidth) / 2;
+            int top = (viewPortHeight - safeHeight) / 2;
+
+            for (int i = 0; i < MAX_ROWS; i++) {
+                mLineBoxes[i].layout(
+                        left,
+                        top + safeHeight * i / MAX_ROWS,
+                        left + safeWidth,
+                        top + safeHeight * (i + 1) / MAX_ROWS);
+            }
+        }
+    }
+};
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ba3cfb6..c29e967 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -78,6 +78,8 @@
 
     int getLastAudibleMasterVolume();
 
+    void setMicrophoneMute(boolean on, String callingPackage);
+
     void setRingerMode(int ringerMode);
 
     int getRingerMode();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index f258063..22db344 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -782,7 +782,7 @@
 
     private void postEventFromNative(
             int what, int arg1, int arg2, Object obj) {
-        if (mEventHandler != null) {
+        if (mEventHandler != null && mNotificationCallback != null) {
             Message msg = mEventHandler.obtainMessage(what, arg1, arg2, obj);
             mEventHandler.sendMessage(msg);
         }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1b92410..e25714a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1649,8 +1649,8 @@
                 mFormat = MediaFormat.createSubtitleFormat(
                     MEDIA_MIMETYPE_TEXT_SUBRIP, language);
             } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                mFormat = MediaFormat.createSubtitleFormat(
-                    MEDIA_MIMETYPE_TEXT_VTT, language);
+                String mime = in.readString();
+                mFormat = MediaFormat.createSubtitleFormat(mime, language);
                 mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
                 mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
                 mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
@@ -1683,12 +1683,40 @@
             dest.writeString(getLanguage());
 
             if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
                 dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
             }
         }
 
+        @Override
+        public String toString() {
+            StringBuilder out = new StringBuilder(128);
+            out.append(getClass().getName());
+            out.append('{');
+            switch (mTrackType) {
+            case MEDIA_TRACK_TYPE_VIDEO:
+                out.append("VIDEO");
+                break;
+            case MEDIA_TRACK_TYPE_AUDIO:
+                out.append("AUDIO");
+                break;
+            case MEDIA_TRACK_TYPE_TIMEDTEXT:
+                out.append("TIMEDTEXT");
+                break;
+            case MEDIA_TRACK_TYPE_SUBTITLE:
+                out.append("SUBTITLE");
+                break;
+            default:
+                out.append("UNKNOWN");
+                break;
+            }
+            out.append(", " + mFormat.toString());
+            out.append("}");
+            return out.toString();
+        }
+
         /**
          * Used to read a TrackInfo from a Parcel.
          */
@@ -1757,6 +1785,12 @@
      */
     public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
 
+    /**
+     * MIME type for CEA-608 closed caption data.
+     * @hide
+     */
+    public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+
     /*
      * A helper function to check if the mime type is supported by media framework.
      */
@@ -1792,16 +1826,11 @@
             }
             SubtitleTrack track = mInbandSubtitleTracks[index];
             if (track != null) {
-                try {
-                    long runID = data.getStartTimeUs() + 1;
-                    // TODO: move conversion into track
-                    track.onData(new String(data.getData(), "UTF-8"), true /* eos */, runID);
-                    track.setRunDiscardTimeMs(
-                            runID,
-                            (data.getStartTimeUs() + data.getDurationUs()) / 1000);
-                } catch (java.io.UnsupportedEncodingException e) {
-                    Log.w(TAG, "subtitle data for track " + index + " is not UTF-8 encoded: " + e);
-                }
+                long runID = data.getStartTimeUs() + 1;
+                track.onData(data.getData(), true /* eos */, runID);
+                track.setRunDiscardTimeMs(
+                        runID,
+                        (data.getStartTimeUs() + data.getDurationUs()) / 1000);
             }
         }
     };
@@ -1872,7 +1901,7 @@
                 }
                 scanner.close();
                 mOutOfBandSubtitleTracks.add(track);
-                track.onData(contents, true /* eos */, ~0 /* runID: keep forever */);
+                track.onData(contents.getBytes(), true /* eos */, ~0 /* runID: keep forever */);
                 return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
             }
 
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 1da0215..ddd5b72 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -60,7 +60,6 @@
 public class MediaRouter {
     private static final String TAG = "MediaRouter";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean USE_SESSIONS = true;
 
     static class Static implements DisplayManager.DisplayListener {
         final Context mAppContext;
@@ -2104,11 +2103,7 @@
         public void setPlaybackType(int type) {
             if (mPlaybackType != type) {
                 mPlaybackType = type;
-                if (USE_SESSIONS) {
-                    configureSessionVolume();
-                } else {
-                    setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type);
-                }
+                configureSessionVolume();
             }
         }
 
@@ -2121,12 +2116,7 @@
         public void setVolumeHandling(int volumeHandling) {
             if (mVolumeHandling != volumeHandling) {
                 mVolumeHandling = volumeHandling;
-                if (USE_SESSIONS) {
-                    configureSessionVolume();
-                } else {
-                    setPlaybackInfoOnRcc(
-                            RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling);
-                }
+                configureSessionVolume();
             }
         }
 
@@ -2139,12 +2129,8 @@
             volume = Math.max(0, Math.min(volume, getVolumeMax()));
             if (mVolume != volume) {
                 mVolume = volume;
-                if (USE_SESSIONS) {
-                    if (mSvp != null) {
-                        mSvp.notifyVolumeChanged();
-                    }
-                } else {
-                    setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume);
+                if (mSvp != null) {
+                    mSvp.notifyVolumeChanged();
                 }
                 dispatchRouteVolumeChanged(this);
                 if (mGroup != null) {
@@ -2184,11 +2170,7 @@
         public void setVolumeMax(int volumeMax) {
             if (mVolumeMax != volumeMax) {
                 mVolumeMax = volumeMax;
-                if (USE_SESSIONS) {
-                    configureSessionVolume();
-                } else {
-                    setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax);
-                }
+                configureSessionVolume();
             }
         }
 
@@ -2199,40 +2181,12 @@
         public void setPlaybackStream(int stream) {
             if (mPlaybackStream != stream) {
                 mPlaybackStream = stream;
-                if (USE_SESSIONS) {
-                    configureSessionVolume();
-                } else {
-                    setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream);
-                }
+                configureSessionVolume();
             }
         }
 
         private void updatePlaybackInfoOnRcc() {
-            if (USE_SESSIONS) {
-                configureSessionVolume();
-            } else {
-                if ((mRcc != null)
-                        && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) {
-                    mRcc.setPlaybackInformation(
-                            RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax);
-                    mRcc.setPlaybackInformation(
-                            RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume);
-                    mRcc.setPlaybackInformation(
-                            RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling);
-                    mRcc.setPlaybackInformation(
-                            RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream);
-                    mRcc.setPlaybackInformation(
-                            RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType);
-                    // let AudioService know whom to call when remote volume
-                    // needs to be updated
-                    try {
-                        sStatic.mAudioService.registerRemoteVolumeObserverForRcc(
-                                mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error registering remote volume observer", e);
-                    }
-                }
-            }
+            configureSessionVolume();
         }
 
         private void configureSessionVolume() {
@@ -2272,12 +2226,6 @@
             }
         }
 
-        private void setPlaybackInfoOnRcc(int what, int value) {
-            if (mRcc != null) {
-                mRcc.setPlaybackInformation(what, value);
-            }
-        }
-
         class SessionVolumeProvider extends RemoteVolumeProvider {
 
             public SessionVolumeProvider(int volumeControl, int maxVolume) {
diff --git a/media/java/android/media/PlayerRecord.java b/media/java/android/media/PlayerRecord.java
index f9708c3..664ddcf 100644
--- a/media/java/android/media/PlayerRecord.java
+++ b/media/java/android/media/PlayerRecord.java
@@ -56,7 +56,7 @@
      */
     final private ComponentName mReceiverComponent;
 
-    private int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+    private int mRccId = -1;
 
     /**
      * A non-null token implies this record tracks a "live" player whose death is being monitored.
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 0caea5f..73bc61a 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -561,6 +561,8 @@
                 return;
             }
             synchronized (mCacheLock) {
+                // Still build the old metadata so when creating a new editor
+                // you get the expected values.
                 // assign the edited data
                 mMetadata = new Bundle(mEditorMetadata);
                 // add the information about editable keys
@@ -570,16 +572,6 @@
                 }
                 mOriginalArtwork = mEditorArtwork;
                 mEditorArtwork = null;
-                if (mMetadataChanged & mArtworkChanged) {
-                    // send to remote control display if conditions are met
-                    sendMetadataWithArtwork_syncCacheLock(null, 0, 0);
-                } else if (mMetadataChanged) {
-                    // send to remote control display if conditions are met
-                    sendMetadata_syncCacheLock(null);
-                } else if (mArtworkChanged) {
-                    // send to remote control display if conditions are met
-                    sendArtwork_syncCacheLock(null, 0, 0);
-                }
 
                 // USE_SESSIONS
                 if (mSession != null && mMetadataBuilder != null) {
@@ -687,14 +679,6 @@
                 // keep track of when the state change occurred
                 mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
 
-                // send to remote control display if conditions are met
-                sendPlaybackState_syncCacheLock(null);
-                // update AudioService
-                sendAudioServiceNewPlaybackState_syncCacheLock();
-
-                // handle automatic playback position refreshes
-                initiateCheckForDrift_syncCacheLock();
-
                 // USE_SESSIONS
                 if (mSession != null) {
                     int pbState = PlaybackState.getStateFromRccState(state);
@@ -707,29 +691,7 @@
         }
     }
 
-    private void initiateCheckForDrift_syncCacheLock() {
-        if (mEventHandler == null) {
-            return;
-        }
-        mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
-        if (!mNeedsPositionSync) {
-            return;
-        }
-        if (mPlaybackPositionMs < 0) {
-            // the current playback state has no known playback position, it's no use
-            // trying to see if there is any drift at this point
-            // (this also bypasses this mechanism for older apps that use the old
-            //  setPlaybackState(int) API)
-            return;
-        }
-        if (playbackPositionShouldMove(mPlaybackState)) {
-            // playback position moving, schedule next position drift check
-            mEventHandler.sendMessageDelayed(
-                    mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
-                    getCheckPeriodFromSpeed(mPlaybackSpeed));
-        }
-    }
-
+    // TODO investigate if we still need position drift checking
     private void onPositionDriftCheck() {
         if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
         synchronized(mCacheLock) {
@@ -781,9 +743,6 @@
             // store locally
             mTransportControlFlags = transportControlFlags;
 
-            // send to remote control display if conditions are met
-            sendTransportControlInfo_syncCacheLock(null);
-
             // USE_SESSIONS
             if (mSession != null) {
                 mSessionPlaybackState.setActions(PlaybackState
@@ -866,17 +825,7 @@
      */
     public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
         synchronized(mCacheLock) {
-            int oldCapa = mPlaybackPositionCapabilities;
-            if (l != null) {
-                mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
-            } else {
-                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
-            }
             mPositionUpdateListener = l;
-            if (oldCapa != mPlaybackPositionCapabilities) {
-                // tell RCDs that this RCC's playback position capabilities have changed
-                sendTransportControlInfo_syncCacheLock(null);
-            }
         }
     }
 
@@ -888,17 +837,7 @@
      */
     public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
         synchronized(mCacheLock) {
-            int oldCapa = mPlaybackPositionCapabilities;
-            if (l != null) {
-                mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
-            } else {
-                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
-            }
             mPositionProvider = l;
-            if (oldCapa != mPlaybackPositionCapabilities) {
-                // tell RCDs that this RCC's playback position capabilities have changed
-                sendTransportControlInfo_syncCacheLock(null);
-            }
             if ((mPositionProvider != null) && (mEventHandler != null)
                     && playbackPositionShouldMove(mPlaybackState)) {
                 // playback position is already moving, but now we have a position provider,
@@ -925,124 +864,12 @@
      */
     public static int MEDIA_POSITION_WRITABLE = 1 << 1;
 
-    private int mPlaybackPositionCapabilities = 0;
-
     /** @hide */
     public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
     /** @hide */
     // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC]
     public final static int DEFAULT_PLAYBACK_VOLUME = 15;
 
-    private int mPlaybackType = PLAYBACK_TYPE_LOCAL;
-    private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME;
-    private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME;
-    private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING;
-    private int mPlaybackStream = AudioManager.STREAM_MUSIC;
-
-    /**
-     * @hide
-     * Set information describing information related to the playback of media so the system
-     * can implement additional behavior to handle non-local playback usecases.
-     * @param what a key to specify the type of information to set. Valid keys are
-     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
-     *        {@link #PLAYBACKINFO_USES_STREAM},
-     *        {@link #PLAYBACKINFO_VOLUME},
-     *        {@link #PLAYBACKINFO_VOLUME_MAX},
-     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
-     * @param value the value for the supplied information to set.
-     */
-    public void setPlaybackInformation(int what, int value) {
-        synchronized(mCacheLock) {
-            switch (what) {
-                case PLAYBACKINFO_PLAYBACK_TYPE:
-                    if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) {
-                        if (mPlaybackType != value) {
-                            mPlaybackType = value;
-                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
-                        }
-                    } else {
-                        Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE");
-                    }
-                    break;
-                case PLAYBACKINFO_VOLUME:
-                    if ((value > -1) && (value <= mPlaybackVolumeMax)) {
-                        if (mPlaybackVolume != value) {
-                            mPlaybackVolume = value;
-                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
-                        }
-                    } else {
-                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME");
-                    }
-                    break;
-                case PLAYBACKINFO_VOLUME_MAX:
-                    if (value > 0) {
-                        if (mPlaybackVolumeMax != value) {
-                            mPlaybackVolumeMax = value;
-                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
-                        }
-                    } else {
-                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX");
-                    }
-                    break;
-                case PLAYBACKINFO_USES_STREAM:
-                    if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) {
-                        mPlaybackStream = value;
-                    } else {
-                        Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM");
-                    }
-                    break;
-                case PLAYBACKINFO_VOLUME_HANDLING:
-                    if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) {
-                        if (mPlaybackVolumeHandling != value) {
-                            mPlaybackVolumeHandling = value;
-                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
-                        }
-                    } else {
-                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING");
-                    }
-                    break;
-                default:
-                    // not throwing an exception or returning an error if more keys are to be
-                    // supported in the future
-                    Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what);
-                    break;
-            }
-        }
-    }
-
-    /**
-     * @hide
-     * Return playback information represented as an integer value.
-     * @param what a key to specify the type of information to retrieve. Valid keys are
-     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
-     *        {@link #PLAYBACKINFO_USES_STREAM},
-     *        {@link #PLAYBACKINFO_VOLUME},
-     *        {@link #PLAYBACKINFO_VOLUME_MAX},
-     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
-     * @return the current value for the given information type, or
-     *   {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or
-     *   the value is unknown.
-     */
-    public int getIntPlaybackInformation(int what) {
-        synchronized(mCacheLock) {
-            switch (what) {
-                case PLAYBACKINFO_PLAYBACK_TYPE:
-                    return mPlaybackType;
-                case PLAYBACKINFO_VOLUME:
-                    return mPlaybackVolume;
-                case PLAYBACKINFO_VOLUME_MAX:
-                    return mPlaybackVolumeMax;
-                case PLAYBACKINFO_USES_STREAM:
-                    return mPlaybackStream;
-                case PLAYBACKINFO_VOLUME_HANDLING:
-                    return mPlaybackVolumeHandling;
-                default:
-                    Log.e(TAG, "getIntPlaybackInformation() unknown key " + what);
-                    return PLAYBACKINFO_INVALID_VALUE;
-            }
-        }
-    }
-
     /**
      * Lock for all cached data
      */
@@ -1102,13 +929,6 @@
      * The current remote control client generation ID across the system, as known by this object
      */
     private int mCurrentClientGenId = -1;
-    /**
-     * The remote control client generation ID, the last time it was told it was the current RC.
-     * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control
-     * client is the "focused" one, and that whenever this client's info is updated, it needs to
-     * send it to the known IRemoteControlDisplay interfaces.
-     */
-    private int mInternalClientGenId = -2;
 
     /**
      * The media button intent description associated with this remote control client
@@ -1134,186 +954,18 @@
     private MediaMetadata mMediaMetadata;
 
     /**
-     * A class to encapsulate all the information about a remote control display.
-     * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
-     */
-    private class DisplayInfoForClient {
-        /** may never be null */
-        private IRemoteControlDisplay mRcDisplay;
-        private int mArtworkExpectedWidth;
-        private int mArtworkExpectedHeight;
-        private boolean mWantsPositionSync = false;
-        private boolean mEnabled = true;
-
-        DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) {
-            mRcDisplay = rcd;
-            mArtworkExpectedWidth = w;
-            mArtworkExpectedHeight = h;
-        }
-    }
-
-    /**
-     * The list of remote control displays to which this client will send information.
-     * Accessed and modified synchronized on mCacheLock
-     */
-    private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1);
-
-    /**
      * @hide
      * Accessor to media button intent description (includes target component)
      */
     public PendingIntent getRcMediaIntent() {
         return mRcMediaIntent;
     }
-    /**
-     * @hide
-     * Accessor to IRemoteControlClient
-     */
-    public IRemoteControlClient getIRemoteControlClient() {
-        return mIRCC;
-    }
-
-    /**
-     * The IRemoteControlClient implementation
-     */
-    private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
-
-        //TODO change name to informationRequestForAllDisplays()
-        public void onInformationRequested(int generationId, int infoFlags) {
-            // only post messages, we can't block here
-            if (mEventHandler != null) {
-                // signal new client
-                mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
-                mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
-                                /*arg1*/ generationId, /*arg2, ignored*/ 0));
-                // send the information
-                mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
-                mEventHandler.removeMessages(MSG_REQUEST_METADATA);
-                mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
-                mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
-                mEventHandler.removeMessages(MSG_REQUEST_METADATA_ARTWORK);
-                mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, null));
-                mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, null));
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK,
-                        0, 0, null));
-            }
-        }
-
-        public void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h) {
-            // only post messages, we can't block here
-            if (mEventHandler != null) {
-                mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, rcd));
-                mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, rcd));
-                if ((w > 0) && (h > 0)) {
-                    mEventHandler.sendMessage(
-                            mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK, w, h, rcd));
-                } else {
-                    mEventHandler.sendMessage(
-                            mEventHandler.obtainMessage(MSG_REQUEST_METADATA, rcd));
-                }
-            }
-        }
-
-        public void setCurrentClientGenerationId(int clientGeneration) {
-            // only post messages, we can't block here
-            if (mEventHandler != null) {
-                mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
-            }
-        }
-
-        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-            // only post messages, we can't block here
-            if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_PLUG_DISPLAY, w, h, rcd));
-            }
-        }
-
-        public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
-            // only post messages, we can't block here
-            if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_UNPLUG_DISPLAY, rcd));
-            }
-        }
-
-        public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
-            // only post messages, we can't block here
-            if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
-            }
-        }
-
-        public void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync) {
-            // only post messages, we can't block here
-            if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_DISPLAY_WANTS_POS_SYNC, wantsSync ? 1 : 0, 0/*arg2 ignored*/, rcd));
-            }
-        }
-
-        public void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled) {
-            // only post messages, we can't block here
-            if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_DISPLAY_ENABLE, enabled ? 1 : 0, 0/*arg2 ignored*/, rcd));
-            }
-        }
-
-        public void seekTo(int generationId, long timeMs) {
-            // only post messages, we can't block here
-            if (mEventHandler != null) {
-                mEventHandler.removeMessages(MSG_SEEK_TO);
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
-                        new Long(timeMs)));
-            }
-        }
-
-        public void updateMetadata(int generationId, int key, Rating value) {
-            // only post messages, we can't block here
-            if (mEventHandler != null) {
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
-            }
-        }
-    };
 
     /**
      * @hide
      * Default value for the unique identifier
      */
     public final static int RCSE_ID_UNREGISTERED = -1;
-    /**
-     * Unique identifier of the RemoteControlStackEntry in AudioService with which
-     * this RemoteControlClient is associated.
-     */
-    private int mRcseId = RCSE_ID_UNREGISTERED;
-    /**
-     * @hide
-     * To be only used by AudioManager after it has received the unique id from
-     * IAudioService.registerRemoteControlClient()
-     * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which
-     *              this RemoteControlClient is associated.
-     */
-    public void setRcseId(int id) {
-        mRcseId = id;
-    }
-
-    /**
-     * @hide
-     */
-    public int getRcseId() {
-        return mRcseId;
-    }
 
     // USE_SESSIONS
     private MediaSession.TransportControlsCallback mTransportListener
@@ -1327,31 +979,13 @@
         @Override
         public void onSetRating(Rating rating) {
             if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
-                if (mEventHandler != null) {
-                    mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                            MSG_UPDATE_METADATA, mCurrentClientGenId,
-                            MetadataEditor.RATING_KEY_BY_USER, rating));
-                }
+                onUpdateMetadata(mCurrentClientGenId, MetadataEditor.RATING_KEY_BY_USER, rating);
             }
         }
     };
 
     private EventHandler mEventHandler;
-    private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
-    private final static int MSG_REQUEST_METADATA = 2;
-    private final static int MSG_REQUEST_TRANSPORTCONTROL = 3;
-    private final static int MSG_REQUEST_ARTWORK = 4;
-    private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5;
-    private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
-    private final static int MSG_PLUG_DISPLAY = 7;
-    private final static int MSG_UNPLUG_DISPLAY = 8;
-    private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
-    private final static int MSG_SEEK_TO = 10;
     private final static int MSG_POSITION_DRIFT_CHECK = 11;
-    private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
-    private final static int MSG_UPDATE_METADATA = 13;
-    private final static int MSG_REQUEST_METADATA_ARTWORK = 14;
-    private final static int MSG_DISPLAY_ENABLE = 15;
 
     private class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1361,63 +995,9 @@
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
-                case MSG_REQUEST_PLAYBACK_STATE:
-                    synchronized (mCacheLock) {
-                        sendPlaybackState_syncCacheLock((IRemoteControlDisplay)msg.obj);
-                    }
-                    break;
-                case MSG_REQUEST_METADATA:
-                    synchronized (mCacheLock) {
-                        sendMetadata_syncCacheLock((IRemoteControlDisplay)msg.obj);
-                    }
-                    break;
-                case MSG_REQUEST_TRANSPORTCONTROL:
-                    synchronized (mCacheLock) {
-                        sendTransportControlInfo_syncCacheLock((IRemoteControlDisplay)msg.obj);
-                    }
-                    break;
-                case MSG_REQUEST_ARTWORK:
-                    synchronized (mCacheLock) {
-                        sendArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
-                                msg.arg1, msg.arg2);
-                    }
-                    break;
-                case MSG_REQUEST_METADATA_ARTWORK:
-                    synchronized (mCacheLock) {
-                        sendMetadataWithArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
-                                msg.arg1, msg.arg2);
-                    }
-                    break;
-                case MSG_NEW_INTERNAL_CLIENT_GEN:
-                    onNewInternalClientGen(msg.arg1);
-                    break;
-                case MSG_NEW_CURRENT_CLIENT_GEN:
-                    onNewCurrentClientGen(msg.arg1);
-                    break;
-                case MSG_PLUG_DISPLAY:
-                    onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
-                    break;
-                case MSG_UNPLUG_DISPLAY:
-                    onUnplugDisplay((IRemoteControlDisplay)msg.obj);
-                    break;
-                case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
-                    onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
-                    break;
-                case MSG_SEEK_TO:
-                    onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
-                    break;
                 case MSG_POSITION_DRIFT_CHECK:
                     onPositionDriftCheck();
                     break;
-                case MSG_DISPLAY_WANTS_POS_SYNC:
-                    onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
-                    break;
-                case MSG_UPDATE_METADATA:
-                    onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
-                    break;
-                case MSG_DISPLAY_ENABLE:
-                    onDisplayEnable((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
-                    break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
             }
@@ -1425,346 +1005,8 @@
     }
 
     //===========================================================
-    // Communication with the IRemoteControlDisplay (the displays known to the system)
-
-    private void sendPlaybackState_syncCacheLock(IRemoteControlDisplay target) {
-        if (mCurrentClientGenId == mInternalClientGenId) {
-            if (target != null) {
-                try {
-                    target.setPlaybackState(mInternalClientGenId,
-                            mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
-                            mPlaybackSpeed);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error in setPlaybackState() for dead display " + target, e);
-                }
-                return;
-            }
-            // target == null implies all displays must be updated
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mEnabled) {
-                    try {
-                        di.mRcDisplay.setPlaybackState(mInternalClientGenId,
-                                mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
-                                mPlaybackSpeed);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    private void sendMetadata_syncCacheLock(IRemoteControlDisplay target) {
-        if (mCurrentClientGenId == mInternalClientGenId) {
-            if (target != null) {
-                try {
-                    target.setMetadata(mInternalClientGenId, mMetadata);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error in setMetadata() for dead display " + target, e);
-                }
-                return;
-            }
-            // target == null implies all displays must be updated
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mEnabled) {
-                    try {
-                        di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e);
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    private void sendTransportControlInfo_syncCacheLock(IRemoteControlDisplay target) {
-        if (mCurrentClientGenId == mInternalClientGenId) {
-            if (target != null) {
-                try {
-                    target.setTransportControlInfo(mInternalClientGenId,
-                            mTransportControlFlags, mPlaybackPositionCapabilities);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error in setTransportControlFlags() for dead display " + target,
-                            e);
-                }
-                return;
-            }
-            // target == null implies all displays must be updated
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mEnabled) {
-                    try {
-                        di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
-                                mTransportControlFlags, mPlaybackPositionCapabilities);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
-                                e);
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    private void sendArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
-        // FIXME modify to cache all requested sizes?
-        if (mCurrentClientGenId == mInternalClientGenId) {
-            if (target != null) {
-                final DisplayInfoForClient di = new DisplayInfoForClient(target, w, h);
-                sendArtworkToDisplay(di);
-                return;
-            }
-            // target == null implies all displays must be updated
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                if (!sendArtworkToDisplay(displayIterator.next())) {
-                    displayIterator.remove();
-                }
-            }
-        }
-    }
-
-    /**
-     * Send artwork to an IRemoteControlDisplay.
-     * @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its
-     *    dimension requirements.
-     * @return false if there was an error communicating with the IRemoteControlDisplay.
-     */
-    private boolean sendArtworkToDisplay(DisplayInfoForClient di) {
-        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
-            Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
-                    di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
-            try {
-                di.mRcDisplay.setArtwork(mInternalClientGenId, artwork);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e);
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private void sendMetadataWithArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
-        // FIXME modify to cache all requested sizes?
-        if (mCurrentClientGenId == mInternalClientGenId) {
-            if (target != null) {
-                try {
-                    if ((w > 0) && (h > 0)) {
-                        Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, w, h);
-                        target.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
-                    } else {
-                        target.setMetadata(mInternalClientGenId, mMetadata);
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error in set(All)Metadata() for dead display " + target, e);
-                }
-                return;
-            }
-            // target == null implies all displays must be updated
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                try {
-                    if (di.mEnabled) {
-                        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
-                            Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
-                                    di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
-                            di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
-                        } else {
-                            di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
-                        }
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e);
-                    displayIterator.remove();
-                }
-            }
-        }
-    }
-
-    //===========================================================
-    // Communication with AudioService
-
-    private static IAudioService sService;
-
-    private static IAudioService getService()
-    {
-        if (sService != null) {
-            return sService;
-        }
-        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
-        sService = IAudioService.Stub.asInterface(b);
-        return sService;
-    }
-
-    private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) {
-        if (mRcseId == RCSE_ID_UNREGISTERED) {
-            return;
-        }
-        //Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value);
-        IAudioService service = getService();
-        try {
-            service.setPlaybackInfoForRcc(mRcseId, what, value);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e);
-        }
-    }
-
-    private void sendAudioServiceNewPlaybackState_syncCacheLock() {
-        if (mRcseId == RCSE_ID_UNREGISTERED) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            service.setPlaybackStateForRcc(mRcseId,
-                    mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setPlaybackStateForRcc", e);
-        }
-    }
-
-    //===========================================================
     // Message handlers
 
-    private void onNewInternalClientGen(int clientGeneration) {
-        synchronized (mCacheLock) {
-            // this remote control client is told it is the "focused" one:
-            // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
-            mInternalClientGenId = clientGeneration;
-        }
-    }
-
-    private void onNewCurrentClientGen(int clientGeneration) {
-        synchronized (mCacheLock) {
-            mCurrentClientGenId = clientGeneration;
-        }
-    }
-
-    /** pre-condition rcd != null */
-    private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        synchronized(mCacheLock) {
-            // do we have this display already?
-            boolean displayKnown = false;
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext() && !displayKnown) {
-                final DisplayInfoForClient di = displayIterator.next();
-                displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
-                if (displayKnown) {
-                    // this display was known but the change in artwork size will cause the
-                    // artwork to be refreshed
-                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
-                        di.mArtworkExpectedWidth = w;
-                        di.mArtworkExpectedHeight = h;
-                        if (!sendArtworkToDisplay(di)) {
-                            displayIterator.remove();
-                        }
-                    }
-                }
-            }
-            if (!displayKnown) {
-                mRcDisplays.add(new DisplayInfoForClient(rcd, w, h));
-            }
-        }
-    }
-
-    /** pre-condition rcd != null */
-    private void onUnplugDisplay(IRemoteControlDisplay rcd) {
-        synchronized(mCacheLock) {
-            Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    displayIterator.remove();
-                    break;
-                }
-            }
-            // list of RCDs has changed, reevaluate whether position check is still needed
-            boolean oldNeedsPositionSync = mNeedsPositionSync;
-            boolean newNeedsPositionSync = false;
-            displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mWantsPositionSync) {
-                    newNeedsPositionSync = true;
-                    break;
-                }
-            }
-            mNeedsPositionSync = newNeedsPositionSync;
-            if (oldNeedsPositionSync != mNeedsPositionSync) {
-                // update needed?
-                initiateCheckForDrift_syncCacheLock();
-            }
-        }
-    }
-
-    /** pre-condition rcd != null */
-    private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) {
-        synchronized(mCacheLock) {
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
-                        ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
-                    di.mArtworkExpectedWidth = w;
-                    di.mArtworkExpectedHeight = h;
-                    if (di.mEnabled) {
-                        if (!sendArtworkToDisplay(di)) {
-                            displayIterator.remove();
-                        }
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    /** pre-condition rcd != null */
-    private void onDisplayWantsSync(IRemoteControlDisplay rcd, boolean wantsSync) {
-        synchronized(mCacheLock) {
-            boolean oldNeedsPositionSync = mNeedsPositionSync;
-            boolean newNeedsPositionSync = false;
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            // go through the list of RCDs and for each entry, check both whether this is the RCD
-            //  that gets upated, and whether the list has one entry that wants position sync
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mEnabled) {
-                    if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                        di.mWantsPositionSync = wantsSync;
-                    }
-                    if (di.mWantsPositionSync) {
-                        newNeedsPositionSync = true;
-                    }
-                }
-            }
-            mNeedsPositionSync = newNeedsPositionSync;
-            if (oldNeedsPositionSync != mNeedsPositionSync) {
-                // update needed?
-                initiateCheckForDrift_syncCacheLock();
-            }
-        }
-    }
-
-    /** pre-condition rcd != null */
-    private void onDisplayEnable(IRemoteControlDisplay rcd, boolean enable) {
-        synchronized(mCacheLock) {
-            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    di.mEnabled = enable;
-                }
-            }
-        }
-    }
-
     private void onSeekTo(int generationId, long timeMs) {
         synchronized (mCacheLock) {
             if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
@@ -1785,42 +1027,6 @@
     // Internal utilities
 
     /**
-     * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap.
-     * If the bitmap fits, then do nothing and return the original.
-     *
-     * @param bitmap
-     * @param maxWidth
-     * @param maxHeight
-     * @return
-     */
-
-    private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
-        if (bitmap != null) {
-            final int width = bitmap.getWidth();
-            final int height = bitmap.getHeight();
-            if (width > maxWidth || height > maxHeight) {
-                float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
-                int newWidth = Math.round(scale * width);
-                int newHeight = Math.round(scale * height);
-                Bitmap.Config newConfig = bitmap.getConfig();
-                if (newConfig == null) {
-                    newConfig = Bitmap.Config.ARGB_8888;
-                }
-                Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig);
-                Canvas canvas = new Canvas(outBitmap);
-                Paint paint = new Paint();
-                paint.setAntiAlias(true);
-                paint.setFilterBitmap(true);
-                canvas.drawBitmap(bitmap, null,
-                        new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
-                bitmap = outBitmap;
-            }
-        }
-        return bitmap;
-    }
-
-
-    /**
      * Returns whether, for the given playback state, the playback position is expected to
      * be changing.
      * @param playstate the playback state to evaluate
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 3711585..76c7299 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -19,11 +19,17 @@
 import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.media.IRemoteControlDisplay;
 import android.media.MediaMetadataEditor;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -34,6 +40,7 @@
 import android.view.KeyEvent;
 
 import java.lang.ref.WeakReference;
+import java.util.List;
 
 /**
  * The RemoteController class is used to control media playback, display and update media metadata
@@ -56,6 +63,7 @@
     private final static int TRANSPORT_UNKNOWN = 0;
     private final static String TAG = "RemoteController";
     private final static boolean DEBUG = false;
+    private final static boolean USE_SESSIONS = true;
     private final static Object mGenLock = new Object();
     private final static Object mInfoLock = new Object();
     private final RcDisplay mRcd;
@@ -64,6 +72,11 @@
     private final int mMaxBitmapDimension;
     private MetadataEditor mMetadataEditor;
 
+    private MediaSessionManager mSessionManager;
+    private MediaSessionManager.SessionListener mSessionListener
+            = new TopTransportSessionListener();
+    private MediaController.Callback mSessionCb = new MediaControllerCallback();
+
     /**
      * Synchronized on mGenLock
      */
@@ -79,6 +92,8 @@
     private int mArtworkWidth = -1;
     private int mArtworkHeight = -1;
     private boolean mEnabled = true;
+    // synchronized on mInfoLock, for USE_SESSION apis.
+    private MediaController mCurrentSession;
 
     /**
      * Class constructor.
@@ -123,6 +138,8 @@
         mContext = context;
         mRcd = new RcDisplay(this);
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        mSessionManager = (MediaSessionManager) context
+                .getSystemService(Context.MEDIA_SESSION_SERVICE);
 
         if (ActivityManager.isLowRamDeviceStatic()) {
             mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
@@ -194,8 +211,15 @@
      * @hide
      */
     public String getRemoteControlClientPackageName() {
-        return mClientPendingIntentCurrent != null ?
-                mClientPendingIntentCurrent.getCreatorPackage() : null;
+        if (USE_SESSIONS) {
+            synchronized (mInfoLock) {
+                return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName()
+                        : null;
+            }
+        } else {
+            return mClientPendingIntentCurrent != null ?
+                    mClientPendingIntentCurrent.getCreatorPackage() : null;
+        }
     }
 
     /**
@@ -215,22 +239,38 @@
      * @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float)
      */
     public long getEstimatedMediaPosition() {
-        if (mLastPlaybackInfo != null) {
-            if (!RemoteControlClient.playbackPositionShouldMove(mLastPlaybackInfo.mState)) {
-                return mLastPlaybackInfo.mCurrentPosMs;
+        if (USE_SESSIONS) {
+            synchronized (mInfoLock) {
+                if (mCurrentSession != null) {
+                    PlaybackState state = mCurrentSession.getPlaybackState();
+                    if (state != null) {
+                        return state.getPosition();
+                    }
+                }
             }
-
-            // Take the current position at the time of state change and estimate.
-            final long thenPos = mLastPlaybackInfo.mCurrentPosMs;
-            if (thenPos < 0) {
-                return -1;
+        } else {
+            final PlaybackInfo lastPlaybackInfo;
+            synchronized (mInfoLock) {
+                lastPlaybackInfo = mLastPlaybackInfo;
             }
+            if (lastPlaybackInfo != null) {
+                if (!RemoteControlClient.playbackPositionShouldMove(lastPlaybackInfo.mState)) {
+                    return lastPlaybackInfo.mCurrentPosMs;
+                }
 
-            final long now = SystemClock.elapsedRealtime();
-            final long then = mLastPlaybackInfo.mStateChangeTimeMs;
-            final long sinceThen = now - then;
-            final long scaledSinceThen = (long) (sinceThen * mLastPlaybackInfo.mSpeed);
-            return thenPos + scaledSinceThen;
+                // Take the current position at the time of state change and
+                // estimate.
+                final long thenPos = lastPlaybackInfo.mCurrentPosMs;
+                if (thenPos < 0) {
+                    return -1;
+                }
+
+                final long now = SystemClock.elapsedRealtime();
+                final long then = lastPlaybackInfo.mStateChangeTimeMs;
+                final long sinceThen = now - then;
+                final long scaledSinceThen = (long) (sinceThen * lastPlaybackInfo.mSpeed);
+                return thenPos + scaledSinceThen;
+            }
         }
         return -1;
     }
@@ -267,30 +307,40 @@
         if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
             throw new IllegalArgumentException("not a media key event");
         }
-        final PendingIntent pi;
-        synchronized(mInfoLock) {
-            if (!mIsRegistered) {
-                Log.e(TAG, "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
-                return false;
-            }
-            if (!mEnabled) {
-                Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
-                return false;
-            }
-            pi = mClientPendingIntentCurrent;
-        }
-        if (pi != null) {
-            Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-            intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-            try {
-                pi.send(mContext, 0, intent);
-            } catch (CanceledException e) {
-                Log.e(TAG, "Error sending intent for media button down: ", e);
+        if (USE_SESSIONS) {
+            synchronized (mInfoLock) {
+                if (mCurrentSession != null) {
+                    return mCurrentSession.dispatchMediaButtonEvent(keyEvent);
+                }
                 return false;
             }
         } else {
-            Log.i(TAG, "No-op when sending key click, no receiver right now");
-            return false;
+            final PendingIntent pi;
+            synchronized (mInfoLock) {
+                if (!mIsRegistered) {
+                    Log.e(TAG,
+                            "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
+                    return false;
+                }
+                if (!mEnabled) {
+                    Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
+                    return false;
+                }
+                pi = mClientPendingIntentCurrent;
+            }
+            if (pi != null) {
+                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                try {
+                    pi.send(mContext, 0, intent);
+                } catch (CanceledException e) {
+                    Log.e(TAG, "Error sending intent for media button down: ", e);
+                    return false;
+                }
+            } else {
+                Log.i(TAG, "No-op when sending key click, no receiver right now");
+                return false;
+            }
         }
         return true;
     }
@@ -311,11 +361,19 @@
         if (timeMs < 0) {
             throw new IllegalArgumentException("illegal negative time value");
         }
-        final int genId;
-        synchronized (mGenLock) {
-            genId = mClientGenerationIdCurrent;
+        if (USE_SESSIONS) {
+            synchronized (mInfoLock) {
+                if (mCurrentSession != null) {
+                    mCurrentSession.getTransportControls().seekTo(timeMs);
+                }
+            }
+        } else {
+            final int genId;
+            synchronized (mGenLock) {
+                genId = mClientGenerationIdCurrent;
+            }
+            mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
         }
-        mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
         return true;
     }
 
@@ -430,7 +488,6 @@
         return editor;
     }
 
-
     /**
      * A class to read the metadata published by a {@link RemoteControlClient}, or send a
      * {@link RemoteControlClient} new values for keys that can be edited.
@@ -477,26 +534,41 @@
             if (!mMetadataChanged) {
                 return;
             }
-            final int genId;
-            synchronized(mGenLock) {
-                genId = mClientGenerationIdCurrent;
-            }
-            synchronized(mInfoLock) {
-                if (mEditorMetadata.containsKey(
-                        String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
-                    Rating rating = (Rating) getObject(
-                            MediaMetadataEditor.RATING_KEY_BY_USER, null);
-                    mAudioManager.updateRemoteControlClientMetadata(genId,
-                          MediaMetadataEditor.RATING_KEY_BY_USER,
-                          rating);
-                } else {
-                    Log.e(TAG, "no metadata to apply");
+            if (USE_SESSIONS) {
+                synchronized (mInfoLock) {
+                    if (mCurrentSession != null) {
+                        if (mEditorMetadata.containsKey(
+                                String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+                            Rating rating = (Rating) getObject(
+                                    MediaMetadataEditor.RATING_KEY_BY_USER, null);
+                            if (rating != null) {
+                                mCurrentSession.getTransportControls().setRating(rating);
+                            }
+                        }
+                    }
                 }
-                // NOT setting mApplied to true as this type of MetadataEditor will be applied
-                // multiple times, whenever the user of a RemoteController needs to change the
-                // metadata (e.g. user changes the rating of a song more than once during playback)
-                mApplied = false;
+            } else {
+                final int genId;
+                synchronized(mGenLock) {
+                    genId = mClientGenerationIdCurrent;
+                }
+                synchronized(mInfoLock) {
+                    if (mEditorMetadata.containsKey(
+                            String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+                        Rating rating = (Rating) getObject(
+                                MediaMetadataEditor.RATING_KEY_BY_USER, null);
+                        mAudioManager.updateRemoteControlClientMetadata(genId,
+                              MediaMetadataEditor.RATING_KEY_BY_USER,
+                              rating);
+                    } else {
+                        Log.e(TAG, "no metadata to apply");
+                    }
+                }
             }
+            // NOT setting mApplied to true as this type of MetadataEditor will be applied
+            // multiple times, whenever the user of a RemoteController needs to change the
+            // metadata (e.g. user changes the rating of a song more than once during playback)
+            mApplied = false;
         }
 
     }
@@ -649,6 +721,46 @@
         }
     }
 
+    /**
+     * This receives updates when the current session changes. This is
+     * registered to receive the updates on the handler thread so it can call
+     * directly into the appropriate methods.
+     */
+    private class MediaControllerCallback extends MediaController.Callback {
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            onNewPlaybackState(state);
+        }
+
+        @Override
+        public void onMetadataChanged(MediaMetadata metadata) {
+            onNewMediaMetadata(metadata);
+        }
+    }
+
+    /**
+     * Listens for changes to the active session stack and replaces the
+     * currently tracked session if it has changed.
+     */
+    private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
+        @Override
+        public void onActiveSessionsChanged(List<MediaController> controllers) {
+            int size = controllers.size();
+            for (int i = 0; i < size; i++) {
+                MediaController controller = controllers.get(i);
+                long flags = controller.getFlags();
+                // We only care about sessions that handle transport controls,
+                // which will be true for apps using RCC
+                if ((flags & MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
+                    updateController(controller);
+                    return;
+                }
+            }
+            updateController(null);
+        }
+
+    }
+
     //==================================================
     // Event handling
     private final EventHandler mEventHandler;
@@ -658,6 +770,8 @@
     private final static int MSG_NEW_METADATA       = 3; // msg always has non-null obj parameter
     private final static int MSG_CLIENT_CHANGE      = 4;
     private final static int MSG_DISPLAY_ENABLE     = 5;
+    private final static int MSG_NEW_PLAYBACK_STATE = 6;
+    private final static int MSG_NEW_MEDIA_METADATA = 7;
 
     private class EventHandler extends Handler {
 
@@ -686,12 +800,46 @@
                 case MSG_DISPLAY_ENABLE:
                     onDisplayEnable(msg.arg1 == 1);
                     break;
+                case MSG_NEW_PLAYBACK_STATE:
+                    // same as new playback info but using new apis
+                    onNewPlaybackState((PlaybackState) msg.obj);
+                    break;
+                case MSG_NEW_MEDIA_METADATA:
+                    onNewMediaMetadata((MediaMetadata) msg.obj);
+                    break;
                 default:
                     Log.e(TAG, "unknown event " + msg.what);
             }
         }
     }
 
+    /**
+     * @hide
+     */
+    void startListeningToSessions() {
+        final ComponentName listenerComponent = new ComponentName(mContext,
+                mOnClientUpdateListener.getClass());
+        mSessionManager.addActiveSessionsListener(mSessionListener, listenerComponent,
+                ActivityManager.getCurrentUser());
+        mSessionListener.onActiveSessionsChanged(mSessionManager
+                .getActiveSessions(listenerComponent));
+        if (DEBUG) {
+            Log.d(TAG, "Registered session listener with component " + listenerComponent
+                    + " for user " + ActivityManager.getCurrentUser());
+        }
+    }
+
+    /**
+     * @hide
+     */
+    void stopListeningToSessions() {
+        mSessionManager.removeActiveSessionsListener(mSessionListener);
+        if (DEBUG) {
+            Log.d(TAG, "Unregistered session listener for user "
+                    + ActivityManager.getCurrentUser());
+        }
+    }
+
     /** If the msg is already queued, replace it with this one. */
     private static final int SENDMSG_REPLACE = 0;
     /** If the msg is already queued, ignore this one and leave the old. */
@@ -713,6 +861,7 @@
         handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
     }
 
+    ///////////// These calls are used by the old APIs with RCC and RCD //////////////////////
     private void onNewPendingIntent(int genId, PendingIntent pi) {
         synchronized(mGenLock) {
             if (mClientGenerationIdCurrent != genId) {
@@ -848,6 +997,86 @@
         }
     }
 
+    ///////////// These calls are used by the new APIs with Sessions //////////////////////
+    private void updateController(MediaController controller) {
+        if (DEBUG) {
+            Log.d(TAG, "Updating controller to " + controller + " previous controller is "
+                    + mCurrentSession);
+        }
+        synchronized (mInfoLock) {
+            if (controller == null) {
+                if (mCurrentSession != null) {
+                    mCurrentSession.removeCallback(mSessionCb);
+                    mCurrentSession = null;
+                    sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+                            0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */);
+                }
+            } else if (mCurrentSession == null
+                    || !controller.getSessionInfo().getId()
+                            .equals(mCurrentSession.getSessionInfo().getId())) {
+                if (mCurrentSession != null) {
+                    mCurrentSession.removeCallback(mSessionCb);
+                }
+                sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+                        0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */);
+                mCurrentSession = controller;
+                mCurrentSession.addCallback(mSessionCb, mEventHandler);
+
+                PlaybackState state = controller.getPlaybackState();
+                sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE,
+                        0 /* genId */, 0, state /* obj */, 0 /* delay */);
+
+                MediaMetadata metadata = controller.getMetadata();
+                sendMsg(mEventHandler, MSG_NEW_MEDIA_METADATA, SENDMSG_REPLACE,
+                        0 /* arg1 */, 0 /* arg2 */, metadata /* obj */, 0 /* delay */);
+            }
+            // else same controller, no need to update
+        }
+    }
+
+    private void onNewPlaybackState(PlaybackState state) {
+        final OnClientUpdateListener l;
+        synchronized (mInfoLock) {
+            l = this.mOnClientUpdateListener;
+        }
+        if (l != null) {
+            int playstate = state == null ? RemoteControlClient.PLAYSTATE_NONE : PlaybackState
+                    .getRccStateFromState(state.getState());
+            if (state == null || state.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
+                l.onClientPlaybackStateUpdate(playstate);
+            } else {
+                l.onClientPlaybackStateUpdate(playstate, state.getLastPositionUpdateTime(),
+                        state.getPosition(), state.getPlaybackRate());
+            }
+            if (state != null) {
+                l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state
+                        .getActions()));
+            }
+        }
+    }
+
+    private void onNewMediaMetadata(MediaMetadata metadata) {
+        if (metadata == null) {
+            // RemoteController only handles non-null metadata
+            return;
+        }
+        final OnClientUpdateListener l;
+        final MetadataEditor metadataEditor;
+        // prepare the received Bundle to be used inside a MetadataEditor
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            boolean canRate = mCurrentSession != null
+                    && mCurrentSession.getRatingType() != Rating.RATING_NONE;
+            long editableKeys = canRate ? MediaMetadataEditor.RATING_KEY_BY_USER : 0;
+            Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata);
+            mMetadataEditor = new MetadataEditor(legacyMetadata, editableKeys);
+            metadataEditor = mMetadataEditor;
+        }
+        if (l != null) {
+            l.onClientMetadataUpdate(metadataEditor);
+        }
+    }
+
     //==================================================
     private static class PlaybackInfo {
         int mState;
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 06063de..b0e182d 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -83,7 +83,7 @@
      * indicating the last section of the run.  Calls from different
      * runs must not be intermixed.
      *
-     * @param data
+     * @param data subtitle data byte buffer
      * @param eos true if this is the last section of the run.
      * @param runID mostly-unique ID for this run of data.  Subtitle cues
      *              with runID of 0 are discarded immediately after
@@ -92,10 +92,8 @@
      *              with other runID-s are discarded at the end of the
      *              run, which defaults to the latest timestamp of
      *              any of its cues (with this runID).
-     *
-     * TODO use ByteBuffer
      */
-    public abstract void onData(String data, boolean eos, long runID);
+    public abstract void onData(byte[] data, boolean eos, long runID);
 
     /**
      * Called when adding the subtitle rendering widget to the view hierarchy,
diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
index 0309334..75133c9 100644
--- a/media/java/android/media/TtmlRenderer.java
+++ b/media/java/android/media/TtmlRenderer.java
@@ -563,28 +563,35 @@
     }
 
     @Override
-    public void onData(String data, boolean eos, long runID) {
-        // implement intermixing restriction for TTML.
-        synchronized(mParser) {
-            if (mCurrentRunID != null && runID != mCurrentRunID) {
-                throw new IllegalStateException(
-                        "Run #" + mCurrentRunID +
-                        " in progress.  Cannot process run #" + runID);
-            }
-            mCurrentRunID = runID;
-            mParsingData += data;
-            if (eos) {
-                try {
-                    mParser.parse(mParsingData, mCurrentRunID);
-                } catch (XmlPullParserException e) {
-                    e.printStackTrace();
-                } catch (IOException e) {
-                    e.printStackTrace();
+    public void onData(byte[] data, boolean eos, long runID) {
+        try {
+            // TODO: handle UTF-8 conversion properly
+            String str = new String(data, "UTF-8");
+
+            // implement intermixing restriction for TTML.
+            synchronized(mParser) {
+                if (mCurrentRunID != null && runID != mCurrentRunID) {
+                    throw new IllegalStateException(
+                            "Run #" + mCurrentRunID +
+                            " in progress.  Cannot process run #" + runID);
                 }
-                finishedRun(runID);
-                mParsingData = "";
-                mCurrentRunID = null;
+                mCurrentRunID = runID;
+                mParsingData += str;
+                if (eos) {
+                    try {
+                        mParser.parse(mParsingData, mCurrentRunID);
+                    } catch (XmlPullParserException e) {
+                        e.printStackTrace();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                    finishedRun(runID);
+                    mParsingData = "";
+                    mCurrentRunID = null;
+                }
             }
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e);
         }
     }
 
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index 7977988..a9374d5 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -1001,22 +1001,28 @@
     }
 
     @Override
-    public void onData(String data, boolean eos, long runID) {
-        // implement intermixing restriction for WebVTT only for now
-        synchronized(mParser) {
-            if (mCurrentRunID != null && runID != mCurrentRunID) {
-                throw new IllegalStateException(
-                        "Run #" + mCurrentRunID +
-                        " in progress.  Cannot process run #" + runID);
+    public void onData(byte[] data, boolean eos, long runID) {
+        try {
+            String str = new String(data, "UTF-8");
+
+            // implement intermixing restriction for WebVTT only for now
+            synchronized(mParser) {
+                if (mCurrentRunID != null && runID != mCurrentRunID) {
+                    throw new IllegalStateException(
+                            "Run #" + mCurrentRunID +
+                            " in progress.  Cannot process run #" + runID);
+                }
+                mCurrentRunID = runID;
+                mParser.parse(str);
+                if (eos) {
+                    finishedRun(runID);
+                    mParser.eos();
+                    mRegions.clear();
+                    mCurrentRunID = null;
+                }
             }
-            mCurrentRunID = runID;
-            mParser.parse(data);
-            if (eos) {
-                finishedRun(runID);
-                mParser.eos();
-                mRegions.clear();
-                mCurrentRunID = null;
-            }
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e);
         }
     }
 
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 7c03907..f0cd785 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -37,6 +37,7 @@
     boolean isTransportControlEnabled();
     void showRoutePicker();
     MediaSessionInfo getSessionInfo();
+    long getFlags();
 
     // These commands are for the TransportController
     void play();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 57a0a54..5ca7daa 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -57,6 +57,7 @@
     private final Object mLock = new Object();
 
     private boolean mCbRegistered = false;
+    private MediaSessionInfo mInfo;
 
     private TransportControls mTransportController;
 
@@ -174,6 +175,21 @@
     }
 
     /**
+     * Get the flags for this session.
+     *
+     * @return The current set of flags for the session.
+     * @hide
+     */
+    public long getFlags() {
+        try {
+            return mSessionBinder.getFlags();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getFlags.", e);
+        }
+        return 0;
+    }
+
+    /**
      * Adds a callback to receive updates from the Session. Updates will be
      * posted on the caller's thread.
      *
@@ -253,12 +269,14 @@
      * @hide
      */
     public MediaSessionInfo getSessionInfo() {
-        try {
-            return mSessionBinder.getSessionInfo();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in getSessionInfo.", e);
+        if (mInfo == null) {
+            try {
+                mInfo = mSessionBinder.getSessionInfo();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in getSessionInfo.", e);
+            }
         }
-        return null;
+        return mInfo;
     }
 
     /*
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 099f601..801844f 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -20,6 +20,10 @@
 import android.app.PendingIntent.CanceledException;
 import android.content.Context;
 import android.content.Intent;
+import android.media.MediaMetadata;
+import android.media.MediaMetadataEditor;
+import android.media.MediaMetadataRetriever;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.ArrayMap;
@@ -64,6 +68,88 @@
         return sInstance;
     }
 
+    public static Bundle getOldMetadata(MediaMetadata metadata) {
+        Bundle oldMetadata = new Bundle();
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUM),
+                    metadata.getString(MediaMetadata.METADATA_KEY_ALBUM));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) {
+            oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+                    metadata.getBitmap(MediaMetadata.METADATA_KEY_ART));
+        } else if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) {
+            // Fall back to album art if the track art wasn't available
+            oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+                    metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST),
+                    metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ARTIST),
+                    metadata.getString(MediaMetadata.METADATA_KEY_ARTIST));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_AUTHOR)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_AUTHOR),
+                    metadata.getString(MediaMetadata.METADATA_KEY_AUTHOR));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPILATION)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPILATION),
+                    metadata.getString(MediaMetadata.METADATA_KEY_COMPILATION));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPOSER)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPOSER),
+                    metadata.getString(MediaMetadata.METADATA_KEY_COMPOSER));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_DATE)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DATE),
+                    metadata.getString(MediaMetadata.METADATA_KEY_DATE));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_DISC_NUMBER)) {
+            oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER),
+                    metadata.getLong(MediaMetadata.METADATA_KEY_DISC_NUMBER));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+            oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DURATION),
+                    metadata.getLong(MediaMetadata.METADATA_KEY_DURATION));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_GENRE)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_GENRE),
+                    metadata.getString(MediaMetadata.METADATA_KEY_GENRE));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) {
+            oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS),
+                    metadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_RATING)) {
+            oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_OTHERS),
+                    metadata.getRating(MediaMetadata.METADATA_KEY_RATING));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_USER_RATING)) {
+            oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER),
+                    metadata.getRating(MediaMetadata.METADATA_KEY_USER_RATING));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_TITLE)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_TITLE),
+                    metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) {
+            oldMetadata.putLong(
+                    String.valueOf(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER),
+                    metadata.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_WRITER)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_WRITER),
+                    metadata.getString(MediaMetadata.METADATA_KEY_WRITER));
+        }
+        if (metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR)) {
+            oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
+                    metadata.getString(MediaMetadata.METADATA_KEY_YEAR));
+        }
+        return oldMetadata;
+    }
+
     public MediaSession getSession(PendingIntent pi) {
         SessionHolder holder = mSessions.get(pi);
         return holder == null ? null : holder.mSession;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 291bfc8..2e6b86e 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -96,10 +96,13 @@
     }
 
     /**
-     * Get a list of controllers for all ongoing sessions. This requires the
-     * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
-     * the calling app. You may also retrieve this list if your app is an
-     * enabled notification listener using the
+     * Get a list of controllers for all ongoing sessions. The controllers will
+     * be provided in priority order with the most important controller at index
+     * 0.
+     * <p>
+     * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+     * permission be held by the calling app. You may also retrieve this list if
+     * your app is an enabled notification listener using the
      * {@link NotificationListenerService} APIs, in which case you must pass the
      * {@link ComponentName} of your enabled listener.
      *
@@ -130,7 +133,8 @@
         ArrayList<MediaController> controllers = new ArrayList<MediaController>();
         try {
             List<IBinder> binders = mService.getSessions(notificationListener, userId);
-            for (int i = binders.size() - 1; i >= 0; i--) {
+            int size = binders.size();
+            for (int i = 0; i < size; i++) {
                 MediaController controller = MediaController.fromBinder(ISessionController.Stub
                         .asInterface(binders.get(i)));
                 controllers.add(controller);
@@ -239,7 +243,8 @@
         /**
          * Called when the list of active sessions has changed. This can be due
          * to a session being added or removed or the order of sessions
-         * changing.
+         * changing. The controllers will be provided in priority order with the
+         * most important controller at index 0.
          *
          * @param controllers The updated list of controllers for the user that
          *            changed.
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index e09ac3f..3b3f249 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -432,6 +432,8 @@
                 return STATE_REWINDING;
             case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
                 return STATE_SKIPPING_TO_PREVIOUS;
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                return STATE_SKIPPING_TO_NEXT;
             case RemoteControlClient.PLAYSTATE_STOPPED:
                 return STATE_STOPPED;
             default:
@@ -440,6 +442,41 @@
     }
 
     /**
+     * Get the {@link RemoteControlClient} state for the given
+     * {@link PlaybackState} state.
+     *
+     * @param state The state used by {@link PlaybackState}.
+     * @return The equivalent state used by {@link RemoteControlClient}.
+     * @hide
+     */
+    public static int getRccStateFromState(int state) {
+        switch (state) {
+            case STATE_BUFFERING:
+                return RemoteControlClient.PLAYSTATE_BUFFERING;
+            case STATE_ERROR:
+                return RemoteControlClient.PLAYSTATE_ERROR;
+            case STATE_FAST_FORWARDING:
+                return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
+            case STATE_NONE:
+                return RemoteControlClient.PLAYSTATE_NONE;
+            case STATE_PAUSED:
+                return RemoteControlClient.PLAYSTATE_PAUSED;
+            case STATE_PLAYING:
+                return RemoteControlClient.PLAYSTATE_PLAYING;
+            case STATE_REWINDING:
+                return RemoteControlClient.PLAYSTATE_REWINDING;
+            case STATE_SKIPPING_TO_PREVIOUS:
+                return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
+            case STATE_SKIPPING_TO_NEXT:
+                return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
+            case STATE_STOPPED:
+                return RemoteControlClient.PLAYSTATE_STOPPED;
+            default:
+                return -1;
+        }
+    }
+
+    /**
      * @hide
      */
     public static long getActionsFromRccControlFlags(int rccFlags) {
@@ -454,6 +491,21 @@
         return actions;
     }
 
+    /**
+     * @hide
+     */
+    public static int getRccControlFlagsFromActions(long actions) {
+        int rccFlags = 0;
+        long action = 1;
+        while (action <= actions && action < Integer.MAX_VALUE) {
+            if ((action & actions) != 0) {
+                rccFlags |= getRccFlagForAction(action);
+            }
+            action = action << 1;
+        }
+        return rccFlags;
+    }
+
     private static long getActionForRccFlag(int flag) {
         switch (flag) {
             case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
@@ -480,6 +532,35 @@
         return 0;
     }
 
+    private static int getRccFlagForAction(long action) {
+        // We only care about the lower set of actions that can map to rcc
+        // flags.
+        int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
+        switch (testAction) {
+            case (int) ACTION_SKIP_TO_PREVIOUS:
+                return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
+            case (int) ACTION_REWIND:
+                return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
+            case (int) ACTION_PLAY:
+                return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
+            case (int) ACTION_PLAY_PAUSE:
+                return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
+            case (int) ACTION_PAUSE:
+                return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
+            case (int) ACTION_STOP:
+                return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
+            case (int) ACTION_FAST_FORWARD:
+                return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
+            case (int) ACTION_SKIP_TO_NEXT:
+                return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
+            case (int) ACTION_SEEK_TO:
+                return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
+            case (int) ACTION_SET_RATING:
+                return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
+        }
+        return 0;
+    }
+
     public static final Parcelable.Creator<PlaybackState> CREATOR
             = new Parcelable.Creator<PlaybackState>() {
         @Override
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 52045d3..3f0405d 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -144,15 +144,41 @@
     /**
      * Builds a URI that points to all programs on a given channel.
      *
+     * @param channelId The ID of the channel to return programs for.
+     */
+    public static final Uri buildProgramsUriForChannel(long channelId) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
+                .appendPath(PATH_CHANNEL).appendPath(String.valueOf(channelId))
+                .appendPath(PATH_PROGRAM).build();
+    }
+
+    /**
+     * Builds a URI that points to all programs on a given channel.
+     *
      * @param channelUri The URI of the channel to return programs for.
      */
     public static final Uri buildProgramsUriForChannel(Uri channelUri) {
         if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
             throw new IllegalArgumentException("Not a channel: " + channelUri);
         }
-        String channelId = String.valueOf(ContentUris.parseId(channelUri));
-        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
-                .appendPath(PATH_CHANNEL).appendPath(channelId).appendPath(PATH_PROGRAM).build();
+        return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
+    }
+
+    /**
+     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
+     * given time frame.
+     *
+     * @param channelId The ID of the channel to return programs for.
+     * @param startTime The start time used to filter programs. The returned programs should have
+     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
+     * @param endTime The end time used to filter programs. The returned programs should have
+     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
+     */
+    public static final Uri buildProgramsUriForChannel(long channelId, long startTime,
+            long endTime) {
+        Uri uri = buildProgramsUriForChannel(channelId);
+        return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
+                .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
     }
 
     /**
@@ -167,9 +193,10 @@
      */
     public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
             long endTime) {
-        Uri uri = buildProgramsUriForChannel(channelUri);
-        return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
-                .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
+        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
+            throw new IllegalArgumentException("Not a channel: " + channelUri);
+        }
+        return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
     }
 
     /**
@@ -272,6 +299,15 @@
         /** A generic channel type. */
         public static final int TYPE_OTHER = 0x0;
 
+        /** The channel type for NTSC. */
+        public static final int TYPE_NTSC = 0x1;
+
+        /** The channel type for PAL. */
+        public static final int TYPE_PAL = 0x2;
+
+        /** The channel type for SECAM. */
+        public static final int TYPE_SECAM = 0x3;
+
         /** The special channel type used for pass-through inputs such as HDMI. */
         public static final int TYPE_PASSTHROUGH = 0x00010000;
 
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 868c5bf..7b8f2ec 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -26,6 +26,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -223,6 +224,18 @@
         return mService.loadLabel(pm);
     }
 
+    /**
+     * Loads the user-displayed icon for this TV input service.
+     *
+     * @param pm Supplies a PackageManager used to load the TV input's resources.
+     * @return a Drawable containing the TV input's icon. If the TV input does not have
+     *         an icon, application icon is returned. If it's unavailable too, system default is
+     *         returned.
+     */
+    public Drawable loadIcon(PackageManager pm) {
+        return mService.serviceInfo.loadIcon(pm);
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 157dd49..fbe5340 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -24,6 +24,7 @@
 #include <SkBitmap.h>
 #include <media/IMediaHTTPService.h>
 #include <media/mediametadataretriever.h>
+#include <media/mediascanner.h>
 #include <private/media/VideoFrame.h>
 
 #include "jni.h"
@@ -337,17 +338,13 @@
         return NULL;
     }
 
-    unsigned int len = mediaAlbumArt->mSize;
-    char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
-    jbyteArray array = env->NewByteArray(len);
+    jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
     if (!array) {  // OutOfMemoryError exception has already been thrown.
         ALOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
     } else {
-        jbyte* bytes = env->GetByteArrayElements(array, NULL);
-        if (bytes != NULL) {
-            memcpy(bytes, data, len);
-            env->ReleaseByteArrayElements(array, bytes, 0);
-        }
+        const jbyte* data =
+                reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+        env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
     }
 
     // No need to delete mediaAlbumArt here
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index b520440..321c2e3 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -348,17 +348,16 @@
     }
 
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    MediaAlbumArt* mediaAlbumArt =
-            reinterpret_cast<MediaAlbumArt*>(mp->extractAlbumArt(fd));
+    MediaAlbumArt* mediaAlbumArt = mp->extractAlbumArt(fd);
     if (mediaAlbumArt == NULL) {
         return NULL;
     }
 
-    jbyteArray array = env->NewByteArray(mediaAlbumArt->mSize);
+    jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
     if (array != NULL) {
-        jbyte* bytes = env->GetByteArrayElements(array, NULL);
-        memcpy(bytes, &mediaAlbumArt->mData[0], mediaAlbumArt->mSize);
-        env->ReleaseByteArrayElements(array, bytes, 0);
+        const jbyte* data =
+                reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+        env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
     }
 
 done:
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 3dd988e..a4d292a 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -104,7 +104,9 @@
     int height;
     meta->findInt32(kKeyWidth, &width);
     meta->findInt32(kKeyHeight, &height);
-    configBitmapSize(bm, getPrefConfig(k32Bit_SrcDepth, false), width, height);
+    configBitmapSize(
+            bm, SkColorTypeToBitmapConfig(getPrefColorType(k32Bit_SrcDepth, false)),
+            width, height);
 
     // mode == DecodeBounds
     if (mode == SkImageDecoder::kDecodeBounds_Mode) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 3f37ed1..b09bc2e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -171,3 +171,8 @@
 {
     return static_cast<Sensor const*>(sensor)->getStringType().string();
 }
+
+int ASensor_getReportingMode(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getReportingMode();
+}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index ec87c6e..2ed3d73 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -170,7 +170,7 @@
             DisplayMetrics metrics = new DisplayMetrics();
             metrics.setToDefaults();
 
-            PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packagePath, 0);
+            PackageParser.ApkLite pkg = PackageParser.parseApkLite(packagePath, 0);
             if (pkg == null) {
                 Slog.w(TAG, "Failed to parse package");
 
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 2917faa..006b1ee 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -56,7 +56,7 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="@dimen/date_owner_info_margin"
             android:layout_gravity="center_horizontal"
-            android:textColor="#99ffffff"
+            android:textColor="#ccffffff"
             android:textSize="@dimen/widget_label_font_size"
             android:ellipsize="marquee"
             android:singleLine="true" />
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 200b42e..f197138 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -31,7 +31,7 @@
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत पिन कोड."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करने के लिए, मेनू दबाएं और फिर 0 दबाएं."</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"फेस अनलॉक के अधिकतम प्रयासों की सीमा पार हो गई"</string>
-    <string name="keyguard_charged" msgid="3272223906073492454">"चार्ज हो गई"</string>
+    <string name="keyguard_charged" msgid="3272223906073492454">"चार्ज हो गई है"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"चार्ज हो रहा है"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"अपना चार्जर कनेक्‍ट करें."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"अनलॉक करने के लिए मेनू दबाएं."</string>
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index e9e9b89..69bf44f 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -63,14 +63,11 @@
     <dimen name="keyguard_muliuser_selector_margin">12dp</dimen>
 
     <!-- Overload default clock widget parameters -->
-    <dimen name="widget_big_font_size">96dp</dimen>
+    <dimen name="widget_big_font_size">120dp</dimen>
     <dimen name="widget_label_font_size">16sp</dimen>
-    <dimen name="bottom_text_spacing_digital">-8dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-16dp</dimen>
 
     <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
          Should be 0 on devices with plenty of room (e.g. tablets) -->
     <dimen name="eca_overlap">0dip</dimen>
-
-    <!-- The vertical margin between the date and the owner info. -->
-    <dimen name="date_owner_info_margin">4dp</dimen>
 </resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index f971522..4b113ff 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -155,15 +155,15 @@
     <dimen name="eca_overlap">-10dip</dimen>
 
     <!-- Default clock parameters -->
-    <dimen name="bottom_text_spacing_digital">-6dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-10dp</dimen>
     <dimen name="label_font_size">14dp</dimen>
-    <dimen name="widget_label_font_size">14sp</dimen>
-    <dimen name="widget_big_font_size">68dp</dimen>
+    <dimen name="widget_label_font_size">16sp</dimen>
+    <dimen name="widget_big_font_size">96dp</dimen>
     <dimen name="big_font_size">120dp</dimen>
 
     <!-- The y translation to apply at the start in appear animations. -->
     <dimen name="appear_y_translation_start">32dp</dimen>
 
     <!-- The vertical margin between the date and the owner info. -->
-    <dimen name="date_owner_info_margin">2dp</dimen>
+    <dimen name="date_owner_info_margin">10dp</dimen>
 </resources>
diff --git a/packages/Keyguard/res/values/donottranslate.xml b/packages/Keyguard/res/values/donottranslate.xml
index 16f5a3e..78636db 100644
--- a/packages/Keyguard/res/values/donottranslate.xml
+++ b/packages/Keyguard/res/values/donottranslate.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Skeleton string format for displaying the date. -->
-    <string name="abbrev_wday_month_day_no_year">EEEMMMMd</string>
+    <string name="abbrev_wday_month_day_no_year">EEEEMMMMd</string>
 
     <!-- Skeleton string format for displaying the time in 12-hour format. -->
     <string name="clock_12hr_format">hm</string>
diff --git a/packages/PrintSpooler/res/drawable/print_button.xml b/packages/PrintSpooler/res/drawable/print_button.xml
index d4b6a82..b59afba 100644
--- a/packages/PrintSpooler/res/drawable/print_button.xml
+++ b/packages/PrintSpooler/res/drawable/print_button.xml
@@ -16,8 +16,7 @@
 -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:tint="@color/print_button_tint_color"
-    android:pinned="true">
+    android:color="@color/print_button_tint_color">
     <item
         android:drawable="@drawable/print_button_background">
     </item>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 876dc01..2810785 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Drukwaglys"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Meer opsies"</string>
     <string name="label_destination" msgid="9132510997381599275">"Bestemming"</string>
     <string name="label_copies" msgid="3634531042822968308">"Afskrifte"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Afskrifte:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papiergrootte"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papiergrootte:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kleur"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Oriëntasie"</string>
     <string name="label_pages" msgid="6300874667546617333">"Bladsye (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Alles"</item>
     <item msgid="6812869625222503603">"Reikwydte"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Kon nie na lêer skryf nie"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Kon nie uitdruktaak genereer nie"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Herprobeer"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Drukker nie beskikbaar nie"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Kanselleer tans …"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index b7f1d7f..dfcc4a1 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"የህትመት አስተላላፊ"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"ተጨማሪ አማራጮች"</string>
     <string name="label_destination" msgid="9132510997381599275">"መድረሻ"</string>
     <string name="label_copies" msgid="3634531042822968308">"ቅጂዎች"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"ቅጂዎች፦"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"የወረቀት መጠን"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"የወረቀት መጠን፦"</string>
     <string name="label_color" msgid="1108690305218188969">"ቀለም"</string>
     <string name="label_orientation" msgid="2853142581990496477">"አቀማመጠ ገፅ"</string>
     <string name="label_pages" msgid="6300874667546617333">"ገጾች (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"ሁሉም"</item>
     <item msgid="6812869625222503603">"ምጥጥነ ገጽታ"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"ወደ ፋይል መጻፍ አልተቻለም"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"የህትመት ስራን ማመንጨት አልተቻለም"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"እንደገና ይሞክሩ"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"አታሚ አይገኝም"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"በመሰረዝ ላይ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index b1a41e6..6c52d16 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Спулер за печат"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Още опции"</string>
     <string name="label_destination" msgid="9132510997381599275">"Местоназначение"</string>
     <string name="label_copies" msgid="3634531042822968308">"Копия"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Копия:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Размер на хартията"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер на хартията:"</string>
     <string name="label_color" msgid="1108690305218188969">"Цвят"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="6300874667546617333">"Страници (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Всички"</item>
     <item msgid="6812869625222503603">"Поредица"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Не можа да се запише във файла"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Заданието за отпечатване не можа да се генерира"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Нов опит"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Няма достъп до принтера"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Анулира се…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index c553a96..53190ab 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Gest. cues impr."</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Més opcions"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destinació"</string>
     <string name="label_copies" msgid="3634531042822968308">"Còpies"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Còpies:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Mida del paper"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Mida del paper:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientació"</string>
     <string name="label_pages" msgid="6300874667546617333">"Pàgines (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Tots"</item>
     <item msgid="6812869625222503603">"Interval"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"No s\'ha pogut escriure al fitxer."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"No s\'ha pogut generar la tasca d\'impressió"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Torna-ho a provar"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impressora no disponible"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"S\'està cancel·lant…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index aff3e95..68e8ec3 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Další možnosti"</string>
     <string name="label_destination" msgid="9132510997381599275">"Cíl"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopie"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Počet kopií:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Velikost papíru"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Velikost papíru:"</string>
     <string name="label_color" msgid="1108690305218188969">"Barva"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientace"</string>
     <string name="label_pages" msgid="6300874667546617333">"STRÁNKY (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Vše"</item>
     <item msgid="6812869625222503603">"Rozsah"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Do souboru nelze zapisovat."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Tiskovou úlohu nelze vytvořit"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Opakovat"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tiskárna je nedostupná."</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Rušení…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 54c9f22..368c3768 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Flere valgmuligheder"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destination"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopier"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopier:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papirstørrelse"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papirstørrelse:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farve"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
     <string name="label_pages" msgid="6300874667546617333">"Sider (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Alle"</item>
     <item msgid="6812869625222503603">"Interval"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Der kunne ikke skrives til filen"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Der kunne ikke genereres et udskriftsjob"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Prøv igen"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printeren er utilgængelig"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Annullerer…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 321c709..8dc52a2 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Druck-Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Weitere Optionen"</string>
     <string name="label_destination" msgid="9132510997381599275">"Ziel"</string>
     <string name="label_copies" msgid="3634531042822968308">"Exemplare"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopien:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papierformat"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papierformat:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farbe"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ausrichtung"</string>
     <string name="label_pages" msgid="6300874667546617333">"Seiten (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Alle"</item>
     <item msgid="6812869625222503603">"Bereich"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Fehler beim Schreiben in Datei"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Druckauftrag konnte nicht generiert werden."</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Erneut versuchen"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Drucker nicht verfügbar"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Vorgang wird abgebrochen..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8050ea5..90e81bd 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Cola de impresión"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Más opciones"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destino"</string>
     <string name="label_copies" msgid="3634531042822968308">"Copias"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Copias:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Tamaño del papel"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño de papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Todas"</item>
     <item msgid="6812869625222503603">"Intervalo"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"No se pudo escribir en el archivo."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Error al generar el trabajo de impresión"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impresora no disponible"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelando…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index f8bf6a4..101831a 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Cola de impresión"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Más opciones"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destino"</string>
     <string name="label_copies" msgid="3634531042822968308">"Copias"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Copias:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Tamaño del papel"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño del papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Todo"</item>
     <item msgid="6812869625222503603">"Intervalo"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Error al escribir en el archivo"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Error al generar el trabajo de impresión"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impresora no disponible"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelando…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 301be4c..24e1e54 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Prindispuuler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Rohkem valikuid"</string>
     <string name="label_destination" msgid="9132510997381599275">"Sihtkoht"</string>
     <string name="label_copies" msgid="3634531042822968308">"Koopiaid"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Koopiad:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Paberi suurus"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Paberi suurus:"</string>
     <string name="label_color" msgid="1108690305218188969">"Värv"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Suund"</string>
     <string name="label_pages" msgid="6300874667546617333">"Lehti (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Kõik"</item>
     <item msgid="6812869625222503603">"Vahemik"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Failile ei saanud kirjutada."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Prinditööd ei saanud luua"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Proovi uuesti"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer pole saadaval"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Tühistamine ..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 8dcaa9c..a92b860 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Taustatulostus"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Lisäasetukset"</string>
     <string name="label_destination" msgid="9132510997381599275">"Kohde"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopiot"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopiot:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Paperikoko"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Paperikoko:"</string>
     <string name="label_color" msgid="1108690305218188969">"Väri"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Suunta"</string>
     <string name="label_pages" msgid="6300874667546617333">"Sivut (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Kaikki"</item>
     <item msgid="6812869625222503603">"Väli"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Tiedostoon kirjoittaminen epäonnistui"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Tulostustyötä ei voitu luoda"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Yritä uudelleen"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tulostin ei ole käytettävissä"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Peruutetaan…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index b37c8ac..b7c0247 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"File d\'att. impr."</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Plus d\'options"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destination"</string>
     <string name="label_copies" msgid="3634531042822968308">"Copies"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Copies :"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Taille du papier"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Taille du papier :"</string>
     <string name="label_color" msgid="1108690305218188969">"Couleur"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="6300874667546617333">"Pages (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Tous"</item>
     <item msgid="6812869625222503603">"Plage"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Impossible d\'écrire dans le fichier"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Impossible de générer la tâche d\'impression"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Imprimante indisponible"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Annulation en cours..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 971039b..3150269 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Spouler impress."</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Plus d\'options"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destination"</string>
     <string name="label_copies" msgid="3634531042822968308">"Copies"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Copies :"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Taille du papier"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Taille du papier :"</string>
     <string name="label_color" msgid="1108690305218188969">"Couleur"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="6300874667546617333">"Pages (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Tout"</item>
     <item msgid="6812869625222503603">"Plage"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Impossible d\'écrire dans le fichier."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Impossible de générer la tâche d\'impression."</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Imprimante indisponible."</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Annulation en cours…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index c46dff8..ad03d7f 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"प्रिंट स्पूलर"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"अधिक विकल्प"</string>
     <string name="label_destination" msgid="9132510997381599275">"गंतव्य"</string>
     <string name="label_copies" msgid="3634531042822968308">"प्रतियां"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"प्रतियां:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"काग़ज़ का आकार"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"काग़ज़ का आकार:"</string>
     <string name="label_color" msgid="1108690305218188969">"रंग"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिविन्‍यास"</string>
     <string name="label_pages" msgid="6300874667546617333">"पृष्‍ठ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"सभी"</item>
     <item msgid="6812869625222503603">"सीमा"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"फ़ाइल पर नहीं लिखा जा सका"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"प्रिंट कार्य जनरेट नहीं किया जा सका"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"पुनः प्रयास करें"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"प्रिंटर अनुपलब्ध है"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"रद्द किया जा रहा है..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 51e750a..215c46b 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Više opcija"</string>
     <string name="label_destination" msgid="9132510997381599275">"Odredište"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopije"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopije:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Veličina papira"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Veličina papira:"</string>
     <string name="label_color" msgid="1108690305218188969">"U boji"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orijentacija"</string>
     <string name="label_pages" msgid="6300874667546617333">"Stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Sve"</item>
     <item msgid="6812869625222503603">"Raspon"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Zapisivanje u datoteku nije uspjelo"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Zadatak ispisa nije generiran"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovno"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Pisač nije dostupan"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Otkazivanje…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index fb193f0..314025d 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Nyomtatásisor-kezelő"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"További lehetőségek"</string>
     <string name="label_destination" msgid="9132510997381599275">"Cél"</string>
     <string name="label_copies" msgid="3634531042822968308">"Példányszám"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Példányszám:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papírméret"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papírméret:"</string>
     <string name="label_color" msgid="1108690305218188969">"Szín"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Tájolás"</string>
     <string name="label_pages" msgid="6300874667546617333">"Oldalszám (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Összes"</item>
     <item msgid="6812869625222503603">"Tartomány"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Nem sikerült írni a fájlba"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Nem sikerült létrehozni a nyomtatási feladatot."</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Újra"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"A nyomtató nem érhető el"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Megszakítás..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 1f1891b..de5c2bfb 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Տպման կարգավար"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Այլ ընտրանքներ"</string>
     <string name="label_destination" msgid="9132510997381599275">"Նպատակակետ"</string>
     <string name="label_copies" msgid="3634531042822968308">"Պատճեններ"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Պատճեններ՝"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Թղթի չափը"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Թղթի չափը՝"</string>
     <string name="label_color" msgid="1108690305218188969">"Գույնը"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Դիրքավորում"</string>
     <string name="label_pages" msgid="6300874667546617333">"Էջեր (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Բոլորը"</item>
     <item msgid="6812869625222503603">"Միջակայք"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Հնարավոր չէ գրել ֆայլում"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Չկարողացանք մշակել տպման աշխատանքը"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Կրկնել"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Տպիչն անհասանելի է"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Չեղարկվում է..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index d5bc1f6..77180c4 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Opsi lainnya"</string>
     <string name="label_destination" msgid="9132510997381599275">"Tujuan"</string>
     <string name="label_copies" msgid="3634531042822968308">"Salinan"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Salinan:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Ukuran kertas"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Ukuran kertas:"</string>
     <string name="label_color" msgid="1108690305218188969">"Warna"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
     <string name="label_pages" msgid="6300874667546617333">"(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>) halaman"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Semua"</item>
     <item msgid="6812869625222503603">"Rentang"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Tidak dapat menulis ke file"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Tidak dapat membuat tugas cetak"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Coba lagi"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer tidak tersedia"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Membatalkan…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 0f9201e..f0ef878 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Altre opzioni"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destinazione"</string>
     <string name="label_copies" msgid="3634531042822968308">"Copie"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Copie:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Dimensioni carta"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Dimensioni carta:"</string>
     <string name="label_color" msgid="1108690305218188969">"A colori"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientamento"</string>
     <string name="label_pages" msgid="6300874667546617333">"Pagine (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Tutte"</item>
     <item msgid="6812869625222503603">"Intervallo"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Impossibile scrivere sul file"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Impossibile generare processo di stampa"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Riprova"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Stampante non disponibile"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Annullamento in corso…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index f01a157..4cc6466 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"印刷スプーラ"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"その他のオプション"</string>
     <string name="label_destination" msgid="9132510997381599275">"印刷先"</string>
     <string name="label_copies" msgid="3634531042822968308">"部数"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"部数:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"用紙サイズ"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"用紙サイズ:"</string>
     <string name="label_color" msgid="1108690305218188969">"カラー選択"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="6300874667546617333">"ページ(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"すべて"</item>
     <item msgid="6812869625222503603">"範囲"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"ファイルに書き込めませんでした"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"印刷ジョブを生成できませんでした"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"再試行"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"プリンタを使用できません"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"キャンセルしています…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index c645a7d..87a1711 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"ბეჭდვის Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"მეტი ვარიანტები"</string>
     <string name="label_destination" msgid="9132510997381599275">"დანიშნულება"</string>
     <string name="label_copies" msgid="3634531042822968308">"ასლები"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"ასლები:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"ფურცლის ზომა"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"ფურცლის ზომა:"</string>
     <string name="label_color" msgid="1108690305218188969">"ფერი"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ორიენტაცია"</string>
     <string name="label_pages" msgid="6300874667546617333">"გვერდები (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"ყველა"</item>
     <item msgid="6812869625222503603">"დიაპაზონი"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"ფაილში ჩაწერა ვერ მოხერხდა"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"ბეჭდვის დავალების გენერაცია ვერ ხერხდება"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"გამეორება"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"პრინტერი მიუწვდომელია"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"უქმდება…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index a456314..cdcb21f 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"បោះពុម្ព​ស្ពូល័រ"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"ជម្រើស​ច្រើន​ទៀត"</string>
     <string name="label_destination" msgid="9132510997381599275">"ទិសដៅ"</string>
     <string name="label_copies" msgid="3634531042822968308">"ច្បាប់​ចម្លង"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"ច្បាប់​ចម្លង៖"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"ទំហំ​​ក្រដាស"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"ទំហំ​ក្រដាស៖"</string>
     <string name="label_color" msgid="1108690305218188969">"ពណ៌"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ទិស"</string>
     <string name="label_pages" msgid="6300874667546617333">"ទំព័រ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"ទាំង​អស់"</item>
     <item msgid="6812869625222503603">"ជួរ"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"មិន​អាច​សរសេរ​ទៅ​កាន់​ឯកសារ"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"មិន​អាច​បង្កើត​ការ​ងារ​បោះពុម្ព"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"ព្យាយាម​ម្ដងទៀត"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"ម៉ាស៊ីន​បោះពុម្ព​​មិន​អាច​ប្រើ​បាន"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"កំពុង​បោះបង់..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index c1ace69..65df4fb 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"인쇄 스풀러"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"옵션 더보기"</string>
     <string name="label_destination" msgid="9132510997381599275">"대상"</string>
     <string name="label_copies" msgid="3634531042822968308">"매수"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"매수:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"용지 크기"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"용지 크기:"</string>
     <string name="label_color" msgid="1108690305218188969">"색상"</string>
     <string name="label_orientation" msgid="2853142581990496477">"방향"</string>
     <string name="label_pages" msgid="6300874667546617333">"페이지 수(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"모두"</item>
     <item msgid="6812869625222503603">"범위"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"PDF 파일을 생성하지 못했습니다."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"인쇄 작업을 생성할 수 없습니다."</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"다시 시도"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"선택한 프린터를 사용할 수 없음"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"취소 중..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index c8c6caa..d06660c 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"ຕົວຈັດຄິວການພິມ"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"ໂຕ​ເລືອກ​ເພີ່ມ​ເຕີມ"</string>
     <string name="label_destination" msgid="9132510997381599275">"ປາຍທາງ"</string>
     <string name="label_copies" msgid="3634531042822968308">"ສຳເນົາ"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"ຈຳ​ນວນສຳ​ເນົາ:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"​ຂະ​ໜາດ​ເຈ້ຍ"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"​ຂະ​ໜາດ​ເຈ້ຍ:"</string>
     <string name="label_color" msgid="1108690305218188969">"ສີ"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ລວງ"</string>
     <string name="label_pages" msgid="6300874667546617333">"(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>) ໜ້າ"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"ທັງໝົດ"</item>
     <item msgid="6812869625222503603">"ໄລຍະ"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"​ບໍ່​ສາ​ມາດ​ຂຽນ​ໄຟ​ລ໌​ໄດ້"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"ບໍ່​ສາ​ມາດ​ສ້າງວຽກພິມໄດ້"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"ລອງໃໝ່"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"​ເຄື່ອງ​ພິມ​ບໍ່​ສາ​ມາດ​ໃຊ້​ໄດ້"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"​ກຳ​ລັງ​ຍົກ​ເລີກ…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 0fff75a..a42bdd9 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Daugiau parinkčių"</string>
     <string name="label_destination" msgid="9132510997381599275">"Paskirties vieta"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopijos"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopijų:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Popieriaus dydis"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Popieriaus dydis:"</string>
     <string name="label_color" msgid="1108690305218188969">"Spalva"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientacija"</string>
     <string name="label_pages" msgid="6300874667546617333">"Puslapiai (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Visi"</item>
     <item msgid="6812869625222503603">"Diapazonas"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Nepavyko įrašyti į failą"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Nepavyko sukurti spausdinimo užduoties"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Bandykite dar kartą"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Spausdintuvas nepasiekiamas"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Atšaukiama…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 55ae463..3afba54 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Citas opcijas"</string>
     <string name="label_destination" msgid="9132510997381599275">"Galamērķis"</string>
     <string name="label_copies" msgid="3634531042822968308">"Eksemplāri"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Eksemplāri:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papīra izmērs"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papīra izmērs:"</string>
     <string name="label_color" msgid="1108690305218188969">"Krāsa"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Virziens"</string>
     <string name="label_pages" msgid="6300874667546617333">"Lapas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Visi"</item>
     <item msgid="6812869625222503603">"Diapazons"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Nevarēja ierakstīt failā."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Nevarēja ģenerēt drukas darbu"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Mēģināt vēlreiz"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printeris nav pieejams."</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Notiek atcelšana…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 7eb9b06..ffe98fe 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Хэвлэгчийн буфер"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Нэмэлт сонголтууд"</string>
     <string name="label_destination" msgid="9132510997381599275">"Хүлээн авагч"</string>
     <string name="label_copies" msgid="3634531042822968308">"Хуулбарууд"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Хуулбар:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Цаасны хэмжээ"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Цаасны хэмжээ:"</string>
     <string name="label_color" msgid="1108690305218188969">"Өнгө"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Чиглэл"</string>
     <string name="label_pages" msgid="6300874667546617333">"(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>) хуудас"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Бүгд"</item>
     <item msgid="6812869625222503603">"Хүрээ"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Файл руу бичиж чадсангүй"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Хэвлэх ажлыг үүсгэж чадсангүй"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Дахин оролдох"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Принтер байхгүй"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Цуцлаж байна..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index fa4abc9..7141aeb 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Penspul Cetakan"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Lagi pilihan"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destinasi"</string>
     <string name="label_copies" msgid="3634531042822968308">"Salinan"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Salinan:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Saiz kertas"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Saiz kertas:"</string>
     <string name="label_color" msgid="1108690305218188969">"Warna"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
     <string name="label_pages" msgid="6300874667546617333">"Halaman (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Semua"</item>
     <item msgid="6812869625222503603">"Julat"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Tidak dapat menulis ke fail"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Tidak dapat menjana kerja cetakan"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Cuba semula"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Pencetak tidak tersedia"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Membatalkan..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 03d5248..8c66bfb 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Utskriftskø"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Flere alternativer"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destinasjon"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopier"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopier:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papirstørrelse"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papirstørrelse:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farge"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
     <string name="label_pages" msgid="6300874667546617333">"Sider (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Alle"</item>
     <item msgid="6812869625222503603">"Område"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Kunne ikke skrive til filen"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Kunne ikke generere utskriftsjobben"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Prøv på nytt"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Skriveren er utilgjengelig"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Avbryter …"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index a2e5391..caa5c80 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Afdrukspooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Meer opties"</string>
     <string name="label_destination" msgid="9132510997381599275">"Bestemming"</string>
     <string name="label_copies" msgid="3634531042822968308">"Aantal exemplaren"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Aantal:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Papierformaat"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Papierformaat:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kleur"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Stand"</string>
     <string name="label_pages" msgid="6300874667546617333">"Pagina\'s (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Alle"</item>
     <item msgid="6812869625222503603">"Bereik"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Kan niet naar bestand schrijven"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Kan de afdruktaak niet genereren"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Opnieuw proberen"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer niet beschikbaar"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Annuleren…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 1500060..d19f2ac 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Bufor wydruku"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Więcej opcji"</string>
     <string name="label_destination" msgid="9132510997381599275">"Miejsce docelowe"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopie"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopie:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Rozmiar papieru"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Rozmiar papieru:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kolor"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientacja"</string>
     <string name="label_pages" msgid="6300874667546617333">"Strony (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Wszystkie"</item>
     <item msgid="6812869625222503603">"Zakres"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Nie można zapisać pliku"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Nie udało się wygenerować zadania drukowania"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Ponów próbę"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Drukarka niedostępna"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Anuluję…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 9bcd0d6..6970730 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Mais opções"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destino"</string>
     <string name="label_copies" msgid="3634531042822968308">"Cópias"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Cópias:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Tamanho do papel"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamanho do papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Cor"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
     <string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Todas"</item>
     <item msgid="6812869625222503603">"Intervalo"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Não foi possível gravar no ficheiro"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Não foi possível gerar a tarefa de impressão"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impressora não disponível"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"A cancelar…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index f10e82e..8b2a6fb 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Sp. de impressão"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Mais opções"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destino"</string>
     <string name="label_copies" msgid="3634531042822968308">"Cópias"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Cópias:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Tamanho do papel"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamanho do papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Cor"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
     <string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Todas"</item>
     <item msgid="6812869625222503603">"Intervalo"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Não foi possível gravar no arquivo"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Não foi possível gerar o trabalho de impressão"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impressora indisponível"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelando..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 18394b0..6706cf6 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Derulator print."</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Mai multe opțiuni"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destinație"</string>
     <string name="label_copies" msgid="3634531042822968308">"Copii"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Copii:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Formatul hârtiei"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Formatul hârtiei:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientare"</string>
     <string name="label_pages" msgid="6300874667546617333">"Pagini (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Toate"</item>
     <item msgid="6812869625222503603">"Interval"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Nu s-a putut scrie în fișier."</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Nu s-a putut genera sarcina de printare"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Reîncercați"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Imprimanta nu este disponibilă"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"În curs de anulare..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index c474752..2256be4 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Спулер печати"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Ещё"</string>
     <string name="label_destination" msgid="9132510997381599275">"Принтер"</string>
     <string name="label_copies" msgid="3634531042822968308">"Копии"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Копии:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Размер бумаги"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер бумаги:"</string>
     <string name="label_color" msgid="1108690305218188969">"Печать"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="6300874667546617333">"СТРАНИЦЫ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Все"</item>
     <item msgid="6812869625222503603">"Диапазон"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Не удалось записать в файл"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Не удалось отправить документ на печать."</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Повторить"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Принтер недоступен"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Отмена…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 59e7f4c..a4f0444 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Zaraďovač tlače"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Ďalšie možnosti"</string>
     <string name="label_destination" msgid="9132510997381599275">"Cieľ"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kópie"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Počet kópií:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Veľkosť papiera"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Veľkosť papiera:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farba"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientácia"</string>
     <string name="label_pages" msgid="6300874667546617333">"STRÁNKY (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Všetky"</item>
     <item msgid="6812869625222503603">"Rozsah"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Do súboru nie je možné zapisovať"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Tlačovú úlohu nie je možné vytvoriť"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Opakovať"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tlačiareň nie je k dispozícii"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Ruší sa..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 3d27d65..672af526 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Tisk. v ozadju"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Več možnosti"</string>
     <string name="label_destination" msgid="9132510997381599275">"Cilj"</string>
     <string name="label_copies" msgid="3634531042822968308">"Št. kopij"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Št. kopij:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Velikost papirja"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Velikost papirja:"</string>
     <string name="label_color" msgid="1108690305218188969">"Barvno"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Postavitev"</string>
     <string name="label_pages" msgid="6300874667546617333">"Št. strani (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Vse"</item>
     <item msgid="6812869625222503603">"Obseg"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"V datoteko ni bilo mogoče zapisovati"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Tiskalnega opravila ni bilo mogoče ustvariti"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Poskusi znova"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tiskalnik ni na voljo"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Preklic …"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index b3c13a0..ad45a93 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Штамп. из мемор."</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Још опција"</string>
     <string name="label_destination" msgid="9132510997381599275">"Одредиште"</string>
     <string name="label_copies" msgid="3634531042822968308">"Копије"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Копије:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Величина папира"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Величина папира:"</string>
     <string name="label_color" msgid="1108690305218188969">"Боја"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Положај"</string>
     <string name="label_pages" msgid="6300874667546617333">"Странице (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Све"</item>
     <item msgid="6812869625222503603">"Опсег"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Уписивање у датотеку није могуће"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Није могуће генерисати задатак за штампање"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Покушајте поново"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Штампач није доступан"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Отказивање..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 58dfa40..a777165 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Utskriftskö"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Fler alternativ"</string>
     <string name="label_destination" msgid="9132510997381599275">"Destination"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopior"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopior:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Pappersstorlek"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Pappersstorlek:"</string>
     <string name="label_color" msgid="1108690305218188969">"Färg"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientering"</string>
     <string name="label_pages" msgid="6300874667546617333">"Sidor (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Alla"</item>
     <item msgid="6812869625222503603">"Intervall"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Det gick inte att skriva till filen"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Det gick inte att skapa utskriftsjobbet"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Försök igen"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Skrivaren är inte tillgänglig"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Avbryter ..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 0bb9790..4c7b3c3 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Programu ya kuandaa Printa kwa ajili ya Kuchapisha"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Chaguo zaidi"</string>
     <string name="label_destination" msgid="9132510997381599275">"Itakapofika"</string>
     <string name="label_copies" msgid="3634531042822968308">"Nakala"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Nakala:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Ukubwa wa karatasi"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Ukubwa wa karatasi:"</string>
     <string name="label_color" msgid="1108690305218188969">"Rangi"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Mkao"</string>
     <string name="label_pages" msgid="6300874667546617333">"Kurasa (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Zote"</item>
     <item msgid="6812869625222503603">"Masafa"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Haikuweza kuandika kwenye faili"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuleta kazi ya kuchapisha"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Jaribu tena"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printa haipatikani"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Inaghairi..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index 91fc544..e3e09d3 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"ตัวเลือกอื่น"</string>
     <string name="label_destination" msgid="9132510997381599275">"ปลายทาง"</string>
     <string name="label_copies" msgid="3634531042822968308">"สำเนา"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"สำเนา:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"ขนาดของกระดาษ"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"ขนาดของกระดาษ:"</string>
     <string name="label_color" msgid="1108690305218188969">"สี"</string>
     <string name="label_orientation" msgid="2853142581990496477">"การวางแนว"</string>
     <string name="label_pages" msgid="6300874667546617333">"หน้า (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"ทั้งหมด"</item>
     <item msgid="6812869625222503603">"ช่วง"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"ไม่สามารถเขียนไปยังไฟล์ได้"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"ไม่สามารถสร้างงานพิมพ์"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"ลองอีกครั้ง"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"ไม่สามารถใช้งานเครื่องพิมพ์ได้"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"กำลังยกเลิก…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 111fee4..bb7d0bf 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Higit pang mga opsyon"</string>
     <string name="label_destination" msgid="9132510997381599275">"Patutunguhan"</string>
     <string name="label_copies" msgid="3634531042822968308">"Mga Kopya"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Dami ng kopya:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Laki ng papel"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Laki ng papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kulay"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Oryentasyon"</string>
     <string name="label_pages" msgid="6300874667546617333">"Mga Pahina (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Lahat"</item>
     <item msgid="6812869625222503603">"Sakop"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Hindi makapag-write sa file"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Hindi mabuo ang pag-print"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Subukang muli"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Hindi available ang printer"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Kinakansela…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index 63fa270..5f81654 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Diğer seçenekler"</string>
     <string name="label_destination" msgid="9132510997381599275">"Hedef"</string>
     <string name="label_copies" msgid="3634531042822968308">"Kopya sayısı"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Kopya sayısı"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Kağıt boyutu"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Kağıt boyutu:"</string>
     <string name="label_color" msgid="1108690305218188969">"Renkli"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Sayfa yönü"</string>
     <string name="label_pages" msgid="6300874667546617333">"Sayfa (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Tümü"</item>
     <item msgid="6812869625222503603">"Aralık"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Dosyaya yazılamadı"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Yazdırma işi oluşturulamadı"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Yeniden dene"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Yazıcı kullanılamıyor"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"İptal ediliyor…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index bb0ee2c..81be680 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Більше опцій"</string>
     <string name="label_destination" msgid="9132510997381599275">"Місце признач-ня"</string>
     <string name="label_copies" msgid="3634531042822968308">"Копії"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Копій:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Розмір паперу"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Розмір паперу:"</string>
     <string name="label_color" msgid="1108690305218188969">"Колір"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Орієнтація"</string>
     <string name="label_pages" msgid="6300874667546617333">"Сторінки (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Усі"</item>
     <item msgid="6812869625222503603">"Діапазон"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Не вдається записати у файл"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Не вдалося створити завдання друку"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Повторити"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Принтер недоступний"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Скасування…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 0c42ccc..84e97fd 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Thêm tùy chọn"</string>
     <string name="label_destination" msgid="9132510997381599275">"Đích"</string>
     <string name="label_copies" msgid="3634531042822968308">"Bản sao"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Bản sao:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Khổ giấy"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Khổ giấy:"</string>
     <string name="label_color" msgid="1108690305218188969">"Màu"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Hướng"</string>
     <string name="label_pages" msgid="6300874667546617333">"Trang (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Tất cả"</item>
     <item msgid="6812869625222503603">"Dãy"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Không thể ghi vào tệp"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Không thể tạo lệnh in"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Thử lại"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Máy in không khả dụng"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Đang hủy…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index c853d54..a904388 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"打印处理服务"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"更多选项"</string>
     <string name="label_destination" msgid="9132510997381599275">"目的地"</string>
     <string name="label_copies" msgid="3634531042822968308">"份数"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"份数:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"纸张尺寸"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"纸张尺寸:"</string>
     <string name="label_color" msgid="1108690305218188969">"颜色"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="6300874667546617333">"页数 (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"全部"</item>
     <item msgid="6812869625222503603">"范围"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"无法写入文件"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"无法生成打印作业"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"重试"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"打印机不可用"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"正在取消…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 5d75382..534d4bf 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"列印多工緩衝處理器"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"更多選項"</string>
     <string name="label_destination" msgid="9132510997381599275">"目的地"</string>
     <string name="label_copies" msgid="3634531042822968308">"份數"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"份數:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"紙張大小"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"紙張大小:"</string>
     <string name="label_color" msgid="1108690305218188969">"顏色"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="6300874667546617333">"頁數 (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"全部"</item>
     <item msgid="6812869625222503603">"範圍"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"無法寫入檔案"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"無法產生列印工作"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"印表機無法使用"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"取消中…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index a2e1637..95960c4 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"列印多工緩衝處理器"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"更多選項"</string>
     <string name="label_destination" msgid="9132510997381599275">"目的地"</string>
     <string name="label_copies" msgid="3634531042822968308">"份數"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"份數:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"紙張大小"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"紙張大小:"</string>
     <string name="label_color" msgid="1108690305218188969">"色彩"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="6300874667546617333">"頁數 (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"全部"</item>
     <item msgid="6812869625222503603">"範圍"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"無法寫入檔案"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"無法產生列印工作"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"印表機無法使用"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"取消中..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index 2837949..f46d2db9a 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -17,16 +17,12 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4469836075319831821">"Ispuli sephrinta"</string>
-    <!-- no translation found for more_options_button (2243228396432556771) -->
-    <skip />
+    <string name="more_options_button" msgid="2243228396432556771">"Izinketho eziningi"</string>
     <string name="label_destination" msgid="9132510997381599275">"Indawo"</string>
     <string name="label_copies" msgid="3634531042822968308">"Amakhophi"</string>
-    <!-- no translation found for label_copies_summary (3861966063536529540) -->
-    <skip />
-    <!-- no translation found for label_paper_size (908654383827777759) -->
-    <skip />
-    <!-- no translation found for label_paper_size_summary (5668204981332138168) -->
-    <skip />
+    <string name="label_copies_summary" msgid="3861966063536529540">"Amakhophi:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"Usayizi wekhasi"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"Usayizi wekhasi"</string>
     <string name="label_color" msgid="1108690305218188969">"Umbala"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Umumo"</string>
     <string name="label_pages" msgid="6300874667546617333">"Amakhasi (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -79,13 +75,9 @@
     <item msgid="7421377442011699994">"Konke"</item>
     <item msgid="6812869625222503603">"Ibanga"</item>
   </string-array>
-    <!-- no translation found for print_write_error_message (5787642615179572543) -->
-    <skip />
+    <string name="print_write_error_message" msgid="5787642615179572543">"Ayikwazanga ukubhala kufayela"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Ayikwazanga ukukhiqiza umsebenzi wokuphrinta"</string>
-    <!-- no translation found for print_error_retry (1426421728784259538) -->
-    <skip />
-    <!-- no translation found for print_error_printer_unavailable (6653128543854282851) -->
-    <skip />
-    <!-- no translation found for print_operation_canceling (5274571823242489160) -->
-    <skip />
+    <string name="print_error_retry" msgid="1426421728784259538">"Zama futhi"</string>
+    <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Iphrinta ayitholakali"</string>
+    <string name="print_operation_canceling" msgid="5274571823242489160">"Iyakhansela…"</string>
 </resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f71cafe..3e0d7e5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -1735,10 +1735,12 @@
             } else if (spinner == mOrientationSpinner) {
                 SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
-                if (orientationItem.value == ORIENTATION_PORTRAIT) {
-                    attributes.copyFrom(attributes.asPortrait());
-                } else {
-                    attributes.copyFrom(attributes.asLandscape());
+                if (mMediaSizeSpinner.getSelectedItem() != null) {
+                    if (orientationItem.value == ORIENTATION_PORTRAIT) {
+                        attributes.copyFrom(attributes.asPortrait());
+                    } else {
+                        attributes.copyFrom(attributes.asLandscape());
+                    }
                 }
             }
 
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 0e025a9..a92ab7e 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -195,4 +195,7 @@
     <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
     <bool name="def_wake_gesture_enabled">true</bool>
 
+    <!-- Default for Settings.Global.GUEST_USER_ENABLED -->
+    <bool name="def_guest_user_enabled">true</bool>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 9b21ae4..09e6a94 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 104;
+    private static final int DATABASE_VERSION = 105;
 
     private Context mContext;
     private int mUserHandle;
@@ -1677,6 +1677,24 @@
             upgradeVersion = 104;
         }
 
+        if (upgradeVersion < 105) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
+                            R.bool.def_guest_user_enabled);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
+            }
+            upgradeVersion = 105;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2410,6 +2428,8 @@
 
             loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
 
+            loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
+                    R.bool.def_guest_user_enabled);
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
diff --git a/packages/SystemUI/res/anim/recents_from_app_enter.xml b/packages/SystemUI/res/anim/recents_from_app_enter.xml
new file mode 100644
index 0000000..6abe8b3
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_app_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="top">
+  <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/fast_out_slow_in"
+         android:duration="0"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_app_exit.xml b/packages/SystemUI/res/anim/recents_from_app_exit.xml
new file mode 100644
index 0000000..1447a5a
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_app_exit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="normal">
+
+    <!-- Animate the view out only after recents is visible -->
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+           android:fillEnabled="true"
+           android:fillBefore="true" android:fillAfter="true"
+           android:interpolator="@android:interpolator/fast_out_slow_in"
+           android:duration="1"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
index 4bd7e82..305a82f 100644
--- a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
@@ -19,10 +19,10 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
-     android:zAdjustment="top">
-  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+     android:zAdjustment="normal">
+  <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
          android:fillEnabled="true"
          android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@android:interpolator/accelerate_cubic"
-         android:duration="250"/>
+         android:interpolator="@android:interpolator/linear"
+         android:duration="200"/>
 </set>
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
index becc9d0..863591f 100644
--- a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
@@ -19,10 +19,10 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
-     android:zAdjustment="normal">
+     android:zAdjustment="top">
   <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
          android:fillEnabled="true"
          android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@android:interpolator/decelerate_cubic"
-         android:duration="250"/>
+         android:interpolator="@android:interpolator/linear_out_slow_in"
+         android:duration="200"/>
 </set>
diff --git a/packages/SystemUI/res/anim/recents_from_unknown_enter.xml b/packages/SystemUI/res/anim/recents_from_unknown_enter.xml
new file mode 100644
index 0000000..f68a143
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_unknown_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="top">
+  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/fast_out_slow_in"
+         android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_unknown_exit.xml b/packages/SystemUI/res/anim/recents_from_unknown_exit.xml
new file mode 100644
index 0000000..31cf26a
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_unknown_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="normal">
+  <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/fast_out_slow_in"
+         android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
new file mode 100644
index 0000000..adcefe0
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="normal">
+  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/fast_out_linear_in"
+         android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
new file mode 100644
index 0000000..863591f
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="top">
+  <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/linear_out_slow_in"
+         android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
deleted file mode 100644
index e6af81e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 873ca7e..b28624f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
index 9d3cf53..9ce434d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 288d36a..51dce69 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
index 266d34d..3f3e288 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
index 0298054..9856cbf 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
index 91e2edf..6910456 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
index 9ed15a7..e8c6ec6 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
index 6f2915b..06dcd20 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
index 3f3b692..240f536 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..d4fdbf3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index 6cd1176..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
deleted file mode 100644
index 5ce8708..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
index 3f7c4b0..e464347 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
index 956bb7c..f8b59e8 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index 86e2947..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d8ab8ea..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
index a53aef1..1b578a6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
index e1b2145..80ecaba 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index dffc059..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index c0209b0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
index 2d8f81d..c7bf2c7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
index 61c6d11..278de42 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index a67ed6d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 6101333..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
index 90eece6..464831c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
index 382cf23..c24132c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca1c8c4..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index cfef88d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
index a4b3b37..bc84f22 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
index ee5f623..f4e219e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca3c541..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 78d4490..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
index 3d21350..ece2e37 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 40fbaec..d524dcf 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 77bef31..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d79f5b7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
index 61b4569..373e84a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
index 1a0312b..e5a102a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index d04916e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d940d34..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
index 8715a11..6b19593 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
index 487a0b1..a5e0686 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index a7cff47..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 0a60bb6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
deleted file mode 100644
index e865f4c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index 225d924..f878093 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
index 7779d57..7780b16 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index 37d17d2..343d0dd 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
index 5e70a07..8e9583b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
index 39a0c07..7d38703 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
index 5bbf3fe..6e186a3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
index 798f62f..12b4042 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
index f8e549a..e2a89c3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
index c7fda96..311720b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..9fc1a3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index 7237f09..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
deleted file mode 100644
index bdf0f67..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 3361e34..67e4ee7 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
index ed52bc3..dfef430 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
index b380327..de6d109 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
index 49df31b..7d0c3fbe 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
index ac45bcd..3baeb52 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
index 9fb4266..d5b48e8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
index 459d011..26d7e7b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
index e1cddde..c49198d 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
index e459f2c..2a21f29 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 0ec4d23..538d7d1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
index 4dedcbe..eb8e80b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
index e55f2bf..1c2c35a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
index a39c3e5..eec613f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
index 80e988f..1c0bad8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
index 4ef12b0d..1293fa8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
index 8ef12a8..96a9cce 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
index c2977c0..9ffc80a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
index 60ec10e..aa9b57b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 8aa6e3a..b343522 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
index e272b62..f2f7b50 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
index bf68b22..383398c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
index 59ef663..53444ab 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
index cf3a5ff..4294937 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
index 2598954..7cb3ee4 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
index 66853db..b017946 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
index c46fd026..e8dd07c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
index 0e84d92..f396ea9 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
index 7e96395e..1b817cf 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
index cb94580..21b7a06 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 382ef39..676fc14 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
index 8d7be53..26f4ba9 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
index 613fba0..ea21b60 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
index 0511ad1..c7d77c2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
index 77fe9b2..ae12cfd 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
index ae78eb0..8c27d45 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
index 5b446b1..c98827c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
deleted file mode 100644
index 83693c1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index a2bb50a..ec2951d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
index 24897ce..5103190 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index aaeeb1b..818aa4f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
index ddee461..254f757 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
index 23a7997..f0de417 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
index 9f200c2..97f1526 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
index 43e9bc2..773fa94 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
index 5c0ba82..8a8e941 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
index b76a0ca..ad7dfc3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..f38de93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index 8d56a1d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
deleted file mode 100644
index 461535c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
deleted file mode 100644
index cebbb15..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
index 79cfcee..77969b8 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
index 7959f65..b171f92 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
index c3bfcfb..ad35c65 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
index 64f6a22..d60229f 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
index 8fd36bc..8fffa8e 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
index 6f30e54..9215055 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
index 024ef8f..bcf7eb1 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
index 6e0b071..a261f85 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
index 9a56987..4c612f7 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..8194605
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index aed300b..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
deleted file mode 100644
index 7b03a11..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_03.xml b/packages/SystemUI/res/drawable/ic_notify_zen.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/ic_qs_location_03.xml
copy to packages/SystemUI/res/drawable/ic_notify_zen.xml
index 956a8c3..c46455b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_03.xml
+++ b/packages/SystemUI/res/drawable/ic_notify_zen.xml
@@ -15,14 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="24dp"
+        android:height="24dp"/>
 
     <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
+        android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_01.xml b/packages/SystemUI/res/drawable/ic_power_low.xml
similarity index 66%
rename from packages/SystemUI/res/drawable/ic_qs_location_01.xml
rename to packages/SystemUI/res/drawable/ic_power_low.xml
index ff37d9a..5bb7aba 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_01.xml
+++ b/packages/SystemUI/res/drawable/ic_power_low.xml
@@ -15,14 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="24.0dp"
+        android:height="24.0dp"/>
 
     <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+        android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM26.0,37.0l-4.0,0.0l0.0,-4.0l4.0,0.0L26.0,37.0zM26.0,30.0l-4.0,0.0L22.0,15.0l4.0,0.0L26.0,30.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_01.xml b/packages/SystemUI/res/drawable/ic_power_saver.xml
similarity index 66%
copy from packages/SystemUI/res/drawable/ic_qs_location_01.xml
copy to packages/SystemUI/res/drawable/ic_power_saver.xml
index ff37d9a..26e7375 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_01.xml
+++ b/packages/SystemUI/res/drawable/ic_power_saver.xml
@@ -15,14 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="24.0dp"
+        android:height="24.0dp"/>
 
     <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+        android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM32.0,28.0l-6.0,0.0l0.0,6.0l-4.0,0.0l0.0,-6.0l-6.0,0.0l0.0,-4.0l6.0,0.0l0.0,-6.0l4.0,0.0l0.0,6.0l6.0,0.0L32.0,28.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
deleted file mode 100644
index dc30a53..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:fill="#FFFFFFFF"
-        android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
new file mode 100644
index 0000000..b6a5cad
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
+
+    <path
+        android:fill="#4DFFFFFF"
+        android:pathData="M41.3,41.7L36.6,37.0L24.0,24.5l-7.1,-7.1L14.0,14.5L8.5,9.0L6.0,11.5l5.6,5.6c-5.1,6.3 -4.7,15.5 1.1,21.4c3.1,3.1 7.2,4.7 11.3,4.7c3.6,0.0 7.1,-1.2 10.1,-3.6l5.4,5.4l2.5,-2.5L41.3,41.7zM24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5c0.0,-2.6 0.9,-5.1 2.4,-7.2l9.6,9.6L24.0,39.2zM24.0,10.2l0.0,9.2l14.5,14.5c2.7,-5.9 1.7,-13.1 -3.2,-18.0L24.0,4.5l0.0,0.0l0.0,0.0L16.6,12.0l2.8,2.8L24.0,10.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_03.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
similarity index 68%
rename from packages/SystemUI/res/drawable/ic_qs_location_03.xml
rename to packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
index 956a8c3..e8d59e0 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_03.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
@@ -19,10 +19,10 @@
         android:height="64dp"/>
 
     <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
 
     <path
         android:fill="#FFFFFFFF"
-        android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
+        android:pathData="M35.3,15.9L24.0,4.5l0.0,0.0l0.0,0.0L12.7,15.9c-6.2,6.2 -6.2,16.4 0.0,22.6c3.1,3.1 7.2,4.7 11.3,4.7s8.2,-1.6 11.3,-4.7C41.6,32.2 41.6,22.1 35.3,15.9zM24.0,39.2L24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5s1.2,-6.2 3.5,-8.5l8.5,-8.5L24.0,39.2z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_02.xml b/packages/SystemUI/res/drawable/ic_qs_location_02.xml
deleted file mode 100644
index bb4465f..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_02.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:fill="#FFFFFFFF"
-        android:pathData="M12.0,4.0c-3.48,0.0 -6.3,2.82 -6.3,6.3C5.7,15.02 12.0,22.0 12.0,22.0s6.3,-6.98 6.3,-11.7C18.3,6.82 15.48,4.0 12.0,4.0zM12.0,12.55c-1.24,0.0 -2.25,-1.01 -2.25,-2.25S10.76,8.05 12.0,8.05c1.24,0.0 2.25,1.01 2.25,2.25S13.24,12.55 12.0,12.55z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_04.xml b/packages/SystemUI/res/drawable/ic_qs_location_04.xml
deleted file mode 100644
index 0c0fb3b..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_04.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:fill="#FFFFFFFF"
-        android:pathData="M12.0,10.0c-2.32,0.0 -4.2,1.88 -4.2,4.2C7.8,17.35 12.0,22.0 12.0,22.0s4.2,-4.65 4.2,-7.8C16.2,11.88 14.32,10.0 12.0,10.0zM12.0,15.7c-0.83,0.0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.83,0.0 1.5,0.67 1.5,1.5S12.83,15.7 12.0,15.7z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_05.xml b/packages/SystemUI/res/drawable/ic_qs_location_05.xml
deleted file mode 100644
index 1a21e2f..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_05.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:fill="#FFFFFFFF"
-        android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_06.xml b/packages/SystemUI/res/drawable/ic_qs_location_06.xml
deleted file mode 100644
index 5642a8a2..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_06.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:fill="#FFFFFFFF"
-        android:pathData="M12.0,16.0c-1.16,0.0 -2.1,0.94 -2.1,2.1C9.9,19.67 12.0,22.0 12.0,22.0s2.1,-2.33 2.1,-3.9C14.1,16.94 13.16,16.0 12.0,16.0zM12.0,18.85c-0.41,0.0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75c0.41,0.0 0.75,0.34 0.75,0.75S12.41,18.85 12.0,18.85z"/>
-    <path
-        android:pathData="M11.99,15c-1.35,0,-2.45,1.1,-2.45,2.45      c0,1.84,2.45,4.55,2.45,4.55s2.45,-2.71,2.45,-4.55C14.44,16.1,13.34,15,11.99,15z M11.99,18.33c-0.48,0,-0.88,-0.39,-0.88,-0.88      s0.39,-0.88,0.88,-0.88c0.48,0,0.87,0.39,0.87,0.88S12.47,18.33,11.99,18.33z"
-        android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_07.xml b/packages/SystemUI/res/drawable/ic_qs_location_07.xml
deleted file mode 100644
index 1ad2ebc..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_07.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:pathData="M12,9c-2.51,0,-4.55,2.04,-4.55,4.55       C7.45,16.96,12,22,12,22s4.55,-5.04,4.55,-8.45C16.55,11.04,14.51,9,12,9z M12,15.18c-0.9,0,-1.63,-0.73,-1.63,-1.62       s0.73,-1.62,1.63,-1.62c0.9,0,1.62,0.73,1.62,1.62S12.9,15.18,12,15.18z"
-        android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_08.xml b/packages/SystemUI/res/drawable/ic_qs_location_08.xml
deleted file mode 100644
index 179bc66..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_08.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:pathData="M12,6c-3.09,0,-5.6,2.51,-5.6,5.6       C6.4,15.8,12,22,12,22s5.6,-6.2,5.6,-10.4C17.6,8.51,15.09,6,12,6z M12,13.6c-1.1,0,-2,-0.9,-2,-2s0.9,-2,2,-2c1.1,0,2,0.9,2,2       S13.1,13.6,12,13.6z"
-        android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_09.xml b/packages/SystemUI/res/drawable/ic_qs_location_09.xml
deleted file mode 100644
index 6169af5..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_09.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:pathData="M12,4c-3.48,0,-6.3,2.82,-6.3,6.3       C5.7,15.02,12,22,12,22s6.3,-6.98,6.3,-11.7C18.3,6.82,15.48,4,12,4z M12,12.55c-1.24,0,-2.25,-1.01,-2.25,-2.25S10.76,8.05,12,8.05       c1.24,0,2.25,1.01,2.25,2.25S13.24,12.55,12,12.55z"
-        android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_10.xml b/packages/SystemUI/res/drawable/ic_qs_location_10.xml
deleted file mode 100644
index 93e2eb4..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_10.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-    <size
-        android:width="64dp"
-        android:height="64dp"/>
-
-    <viewport
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"/>
-
-    <path
-        android:pathData="M12,3C8.33,3,5.35,5.98,5.35,9.65       C5.35,14.64,12,22,12,22s6.65,-7.36,6.65,-12.35C18.65,5.98,15.67,3,12,3z M12,12.02c-1.31,0,-2.38,-1.06,-2.38,-2.38       S10.69,7.28,12,7.28c1.31,0,2.37,1.06,2.37,2.37S13.31,12.02,12,12.02z"
-        android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
index d28d347..26ebfbf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2014 The Android Open Source Project
 
@@ -14,18 +13,19 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="true">
-    <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
-</animation-list>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
+
+    <path
+        android:fill="#4DFFFFFF"
+        android:pathData="M24.0,13.0c2.8,0.0 5.0,2.2 5.0,5.0c0.0,1.5 -0.7,2.8 -1.7,3.7l7.3,7.3c2.0,-3.7 3.4,-7.6 3.4,-11.0c0.0,-7.7 -6.3,-14.0 -14.0,-14.0c-4.0,0.0 -7.5,1.6 -10.1,4.3l6.4,6.4C21.2,13.6 22.5,13.0 24.0,13.0zM32.7,32.2l-9.3,-9.3l-0.2,-0.2L6.5,6.0L4.0,8.5l6.4,6.4c-0.2,1.0 -0.4,2.0 -0.4,3.1c0.0,10.5 14.0,26.0 14.0,26.0s3.3,-3.7 6.8,-8.7l6.7,6.7l2.5,-2.5L32.7,32.2z"/>
+    <path
+        android:pathData="M23.5,22.9l0.0,0.0 -0.20000076,-0.19999886z"
+        android:fill="#4DFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
index 72512ac..bc73005 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2014 The Android Open Source Project
 
@@ -14,18 +13,16 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="true">
-    <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
-    <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
-</animation-list>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M24.0,4.0c-7.7,0.0 -14.0,6.3 -14.0,14.0c0.0,10.5 14.0,26.0 14.0,26.0s14.0,-15.5 14.0,-26.0C38.0,10.3 31.7,4.0 24.0,4.0zM24.0,23.0c-2.8,0.0 -5.0,-2.2 -5.0,-5.0s2.2,-5.0 5.0,-5.0c2.8,0.0 5.0,2.2 5.0,5.0S26.8,23.0 24.0,23.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_11.xml b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
similarity index 71%
rename from packages/SystemUI/res/drawable/ic_qs_location_11.xml
rename to packages/SystemUI/res/drawable/stat_sys_no_sim.xml
index 09a3e63..70948b7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_11.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
@@ -15,14 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="18dp"
+        android:height="18dp"/>
 
     <viewport
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"/>
 
     <path
-        android:pathData="M12,2C8.13,2,5,5.13,5,9c0,5.25,7,13,7,13s7,-7.75,7,-13       C19,5.13,15.87,2,12,2z M12,11.5c-1.38,0,-2.5,-1.12,-2.5,-2.5s1.12,-2.5,2.5,-2.5c1.38,0,2.5,1.12,2.5,2.5S13.38,11.5,12,11.5z"
-        android:fill="#4DFFFFFF"/>
+        android:fill="#4DFFFFFF"
+        android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/>
 </vector>
diff --git a/packages/SystemUI/res/layout/battery_low.xml b/packages/SystemUI/res/layout/battery_low.xml
deleted file mode 100644
index 2373355..0000000
--- a/packages/SystemUI/res/layout/battery_low.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/layout/keyguard.xml
-**
-** 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.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/padding"
-    android:orientation="vertical"
-    android:gravity="center"
-    android:padding="16dp"
-    >
-
-    <TextView android:id="@+id/subtitle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textSize="18sp"
-        android:textColor="#ffffffff"
-        android:gravity="start"
-        android:text="@string/battery_low_subtitle"
-        />
-    
-    <TextView android:id="@+id/level_percent"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textSize="18sp"
-        android:textColor="#ffffffff"
-        android:gravity="start"
-        android:paddingBottom="16dp"
-        />
-
-    <ImageView android:id="@+id/image"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:src="@drawable/battery_low_battery"
-        />
-
-</LinearLayout>
-
-
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 9bf42b2..db5983b 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -46,7 +46,7 @@
         android:id="@+id/keyguard_indication_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="100dp"
+        android:layout_marginBottom="70dp"
         android:layout_gravity="bottom|center_horizontal"
         android:textStyle="italic"
         android:textColor="#ffffff"
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index ac6450b..c0ddde1 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -21,7 +21,6 @@
     android:gravity="center"
     android:textSize="20sp"
     android:textColor="#ffffffff"
-    android:textStyle="italic"
     android:text="@string/recents_empty_message"
     android:fontFamily="sans-serif-light"
     android:visibility="gone" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml b/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
index 463fee8..4245d49 100644
--- a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
+++ b/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
@@ -20,4 +20,4 @@
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal|bottom"
     android:scaleType="fitXY"
-    android:src="@drawable/recents_nav_bar_background" />
\ No newline at end of file
+    android:src="@drawable/recents_lower_gradient" />
\ 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 85d2f16..23f2796 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -56,6 +56,7 @@
             android:layout_marginEnd="4dp"
             android:layout_gravity="center_vertical|end"
             android:padding="18dp"
+            android:visibility="invisible"
             android:src="@drawable/recents_dismiss_light" />
     </com.android.systemui.recents.views.TaskBarView>
 </com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index d24d21e..353368b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -63,8 +63,9 @@
     <ImageButton android:id="@+id/settings_button"
         style="@android:style/Widget.Material.Button.Borderless"
         android:layout_toStartOf="@id/multi_user_switch"
-        android:layout_width="56dp"
+        android:layout_width="48dp"
         android:layout_height="@dimen/status_bar_header_height"
+        android:layout_marginStart="8dp"
         android:src="@drawable/ic_settings_24dp"
         android:contentDescription="@string/accessibility_desc_quick_settings"/>
 
@@ -72,7 +73,7 @@
         android:layout_width="wrap_content"
         android:layout_height="@dimen/status_bar_header_height"
         android:layout_toStartOf="@id/multi_user_switch"
-        android:layout_marginEnd="4dp"
+        android:layout_marginEnd="2dp"
         android:layout_marginStart="16dp"
         />
 
@@ -117,12 +118,11 @@
             android:layout_below="@id/clock"
             />
     </RelativeLayout>
-
     <com.android.keyguard.CarrierText
         android:id="@+id/keyguard_carrier_text"
         android:layout_width="match_parent"
         android:layout_height="@dimen/status_bar_header_height_keyguard"
-        android:layout_marginLeft="8dp"
+        android:layout_marginLeft="16dp"
         android:layout_toStartOf="@id/system_icons_container"
         android:gravity="center_vertical"
         android:ellipsize="marquee"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
index 84d64b9..e220a16 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -18,48 +18,13 @@
 <com.android.systemui.statusbar.SpeedBumpView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:focusable="true"
-    android:clickable="true"
+    android:layout_height="@dimen/speed_bump_height"
     android:visibility="gone"
     >
-    <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/speed_bump_height_collapsed"
-            android:layout_gravity="top"
-            android:orientation="horizontal">
-        <com.android.systemui.statusbar.AlphaOptimizedView
-            android:id="@+id/speedbump_line_left"
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1"
-            android:background="#6fdddddd"
-            android:layout_gravity="center_vertical"/>
-        <com.android.systemui.statusbar.SpeedBumpDotsLayout
-                android:id="@+id/speed_bump_dots_layout"
-                android:layout_width="34dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:layout_height="match_parent"
-                android:layout_weight="0"/>
-        <com.android.systemui.statusbar.AlphaOptimizedView
-            android:id="@+id/speedbump_line_right"
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1"
-            android:background="#6fdddddd"
-            android:layout_gravity="center_vertical"/>
-    </LinearLayout>
-    <TextView
-            android:id="@+id/speed_bump_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            android:fontFamily="sans-serif-condensed"
-            android:textSize="15sp"
-            android:singleLine="true"
-            android:textColor="#eeeeee"
-            android:visibility="invisible"
-            android:text="@string/speed_bump_explanation"
-            android:paddingTop="4dp" />
+    <com.android.systemui.statusbar.AlphaOptimizedView
+        android:id="@+id/speedbump_line"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="#6fdddddd"
+        android:layout_gravity="center_vertical"/>
 </com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/layout/user_switcher_item.xml b/packages/SystemUI/res/layout/user_switcher_item.xml
index 43a85e7..8df2f5a 100644
--- a/packages/SystemUI/res/layout/user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/user_switcher_item.xml
@@ -21,10 +21,12 @@
         android:layout_width="match_parent"
         android:layout_height="64dp"
         android:orientation="horizontal"
+        android:gravity="center_vertical"
         tools:context=".settings.UserSwitcherDialog">
     <ImageView
-            android:layout_width="64dp"
-            android:layout_height="match_parent"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_marginStart="4dp"
             android:id="@+id/user_picture"
             tools:src="@drawable/dessert_zombiegingerbread"/>
     <TextView
@@ -37,4 +39,11 @@
             android:gravity="center_vertical"
             tools:text="Hiroshi Lockheimer"
             />
+    <ImageView
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_marginEnd="4dp"
+            android:src="@*android:drawable/ic_menu_delete"
+            android:id="@+id/user_delete"
+            android:background="?android:attr/selectableItemBackground"/>
 </LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a2ef9e6..d9c4c0c 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen kennisgewings"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Voortdurend"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Kennisgewings"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Koppel herlaaier"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Die battery raak pap."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Battery is amper pap"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> oor"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> oor. Batteryspaarder is aan."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie.\nGebruik net die laaier wat verskaf is."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Batterygebruik"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Laai met USB word nie gesteun nie."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik slegs die laaier wat verskaf is."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Instellings"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Aktiveer batteryspaarder?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Begin"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Aktiveer batteryspaarder"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Om die batteryleeftyd te help verbeter, sal Batteryspaarder jou toestel se werkverrigting verminder.\n\nBatteryspaarder sal gedeaktiveer word wanneer jou toestel ingeprop word."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Geen onlangse programme nie"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laai tans"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot vol"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Laai nie"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Soek"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Sleep links vir kamera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat jy dit afskakel"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gas"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ gas"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minute lank"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Een uur lank"</item>
     <item quantity="other" msgid="5408537517529822157">"%d uur lank"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteryspaarder is aan"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Toestel se werkverrigting is verminder."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Maak batteryspaarder se instellings oop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6aeb6d6..f84f028 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ምንም ማሳወቂያዎች የሉም"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"በመካሄድ ላይ ያለ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ማሳወቂያዎች"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"የኃይል መሙያ አገናኝ።"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"ባትሪው እያነሰ ነው።"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"የባትሪ ኃይል አነስተኛ ነው"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ቀሪ"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ይቀራል። የባትሪ ኃይል ቆጣቢ በርቷል።"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።\n የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"የባትሪ ጥቅም"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"የUSB ኃይል መሙላት አይደገፍም።"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"የቀረበውን ኃይል መሙያ ብቻ ይጠቀሙ።"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"ቅንብሮች"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"የባህሪ ኃይል ቆጣቢው ይጀመር?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ጀምር"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"የባህሪ ኃይል ቆጣቢው ይጀመር"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"የባትሪ በህይወት የመቆየት ጊዜን ለማሻሻል እንዲያግዝ፣ የባትሪ ኃይል ቆጣቢው የመሳሪያዎን የመስራት አቅም ይቀንሰዋል።\n\nየባትሪ ኃይል ቆጣቢው መሳሪያዎ የተሰካ ሲሆን ይሰናከላል።"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ቅንብሮች"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"የአውሮፕላን ሁነታ"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"ምንም የቅርብ ጊዜ መተግበሪያዎች የሉም"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"ኃይል በመሙላት ላይ"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> እስኪሞላ ድረስ"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ባትሪ እየሞላ አይደለም"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"ለካሜራ ወደግራ ያንሸራትቱ"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"ይህን እስኪያጠፉት ድረስ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"እንግዳ"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ እንግዳ"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ለአንድ ደቂቃ"</item>
     <item quantity="other" msgid="6924190729213550991">"ለ%d ደቂቃዎች"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"ለአንድ ሰዓት"</item>
     <item quantity="other" msgid="5408537517529822157">"ለ%d ሰዓቶች"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"የመሳሪያው የአሰራር ብቃት ተቀንሷል።"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"የባትሪ ኃይል ቆጣቢ ቅንብሮች"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1aec6fd..44e6ffe 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ليس هناك أي اشعارات"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"مستمر"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"الإشعارات"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"توصيل الشاحن"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"انخفضت طاقة البطارية."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"البطارية منخفضة"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"المتبقي: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"يتبقى <xliff:g id="NUMBER">%d%%</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"استخدام البطارية"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"‏لا يمكن إجراء الشحن عبر USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"لا تستخدم سوى الشاحن المزوّد."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"الإعدادات"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"هل تريد بدء وضع توفير الطاقة؟"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"بدء"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"بدء وضع توفير الطاقة"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"للمساعدة في إطالة عمر البطارية، فإن وضع توفير الطاقة سيقلل من أداء جهازك.\n\nسيتم تعطيل وضع توفير الطاقة عند توصيل جهازك بالشاحن."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"الإعدادات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"وضع الطائرة"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"ليست هناك تطبيقات حديثة"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"جارٍ الشحن"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> حتى الاكتمال"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"لا يتم الشحن"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
     <string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"مرر سريعًا إلى اليمين لفتح الكاميرا"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"لحين تعطيل هذا الإعداد"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"المدعو"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ مدعو"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item>
     <item quantity="other" msgid="6924190729213550991">"‏لمدة %d من الدقائق"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"لمدة ساعة واحدة"</item>
     <item quantity="other" msgid="5408537517529822157">"‏لمدة %d من الساعات"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"تم تقليل أداء الجهاز."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"فتح إعدادات وضع توفير الطاقة"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e16cdd3..71fb8b8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Няма известия"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"В момента"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известия"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Включете зарядното устройство"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерията се изтощава."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Батерията е изтощена"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>. Режимът за запазване на батерията е включен."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB.\nИзползвайте само доставеното зарядно устройство."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Използване на батерията"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Зареждането през USB не се поддържа."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Използвайте само предоставеното зарядно устройство."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Настройки"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Да се стартира ли режимът за запазване на батерията?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Стартиране"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Стартиране на режима за запазване на батерията"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"С цел удължаване на живота на батерията режимът за запазването й ще намали ефективността на устройството ви.\n\nКогато то е включено в захранването, режимът ще се деактивира."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Самолетен режим"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Няма скорошни приложения"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарежда се"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до пълно зареждане"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не се зарежда"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Търсене"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Плъзнете нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Прекарайте пръст наляво, за да включите камерата"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ гост"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"За една минута"</item>
     <item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"За един час"</item>
     <item quantity="other" msgid="5408537517529822157">"За %d часа"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Режимът за запазване на батерията е включен"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Ефективността на устройството е намалена."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отваряне на настройките за режима за запазване на батерията"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ad08dab..becd731 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Cap notificació"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continu"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Connecta el carregador"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"La bateria comença a estar baixa."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Queda un <xliff:g id="NUMBER">%d%%</xliff:g>. La funció Estalvi de bateria està activada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Càrrega d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Ús de la bateria"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"La càrrega per USB no és compatible."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Fes servir només el carregador proporcionat amb el dispositiu."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Configuració"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vols iniciar la funció Estalvi de bateria?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Inicia"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Inicia la funció Estalvi de bateria"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"La funció Estalvi de bateria reduirà el rendiment del dispositiu per tal d\'augmentar la durada de la bateria.\n\nAquesta funció es desactivarà quan el dispositiu estigui connectat."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuració"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode d\'avió"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"No hi ha aplicacions recents."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No s\'està carregant"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Fes lliscar el dit cap a l\'esquerra per obrir la càmera."</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Fins que no ho desactivis"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Convidat"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidat"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durant un minut"</item>
     <item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Durant una hora"</item>
     <item quantity="other" msgid="5408537517529822157">"Durant %d hores"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"La funció Estalvi de bateria està activada."</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"S\'ha reduït el rendiment del dispositiu."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Obre la configuració de la funció Estalvi de bateria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5a08251..97efe46 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žádná oznámení"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Připojte nabíječku"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterie je vybitá."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Baterie je slabá"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>. Režim Úspora baterie je zapnutý."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Nabíjení pomocí rozhraní USB není podporováno.\nPoužívejte pouze nabíječku, která byla dodána se zařízením."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Využití baterie"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjení přes USB není podporováno."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Používejte pouze nabíječku, která je součástí balení."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Nastavení"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Aktivovat režim Úspora baterie?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Spustit"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Aktivovat režim Úspora baterie"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"V režimu Úspora baterie se omezí výkon zařízení, aby se tak prodloužila výdrž baterie.\n\nRežim Úspora baterie se deaktivuje, když bude zařízení zapojeno do zásuvky."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavení"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V letadle"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Žádné nedávné aplikace"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíjení"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do plného nabití"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenabíjí se"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Vyhledávání"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Přejeďte prstem nahoru: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otevřete přejetím prstem vlevo."</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Dokud tuto funkci nevypnete"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Host"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Přidat hosta"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item>
     <item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Na jednu hodinu"</item>
     <item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Výkon zařízení je snížen."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otevřít nastavení režimu Úspora baterie"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 50c3dbb..a86157d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen underretninger"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Tilslut oplader"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er ved at være fladt."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Batteriniveauet er lavt"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage. Batteribesparende er slået til."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke.\nBrug kun den medfølgende oplader."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Batteriforbrug"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB-opladning understøttes ikke."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Brug kun den oplader, der føler med."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Indstillinger"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vil du starte Batteribesparende?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Startet"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Start Batteribesparende"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"For at hjælpe med at forbedre batteriets levetid, reducerer Batteribesparende enhedens ydeevne.\n\nBatteribesparende slukkes, når strømstikket er sat i."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Indstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flytilstand"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Der er ingen seneste apps"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Oplader"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> indtil fuld opladet"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Oplader ikke"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Stryg til venstre for at åbne kameraet"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gæst"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Gæst"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"I ét minut"</item>
     <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"I én time"</item>
     <item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteribesparende er slået til"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Enhedens ydeevne reduceres."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åbn indstillinger for Batteribesparende"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 27523d8..40e623a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Keine Benachrichtigungen"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Ladegerät anschließen"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Akku ist fast leer."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Akku ist schwach"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>. Energiesparmodus ist aktiviert."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwenden Sie das mitgelieferte Aufladegerät."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Akkuverbrauch"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Laden per USB wird nicht unterstützt."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Verwenden Sie nur das im Lieferumfang enthaltene Ladegerät."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Einstellungen"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Energiesparmodus starten?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Starten"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Energiesparmodus starten"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Im Energiesparmodus wird zur Schonung des Akkus die Leistung des Geräts herabgesetzt.\n\nSobald Ihr Gerät an eine Stromquelle angeschlossen ist, wird der Energiesparmodus deaktiviert."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Einstellungen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flugmodus"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Keine neuen Apps"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Wird aufgeladen"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Voll in <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Wird nicht aufgeladen"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
     <string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Zum Öffnen der Kamera nach links wischen"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Bis zur Deaktivierung"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Für eine Minute"</item>
     <item quantity="other" msgid="6924190729213550991">"Für %d Minuten"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Für eine Stunde"</item>
     <item quantity="other" msgid="5408537517529822157">"Für %d Stunden"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Die Geräteleistung wurde herabgesetzt."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Einstellungen für den Energiesparmodus öffnen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c0d586e..5e5aa6a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Δεν υπάρχουν ειδοποιήσεις"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Συνδέστε φορτιστή"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Η στάθμη της μπαταρίας είναι χαμηλή."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Χαμηλή στάθμη μπαταρίας"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>. Η Εξοικονόμηση μπαταρίας είναι ενεργή."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB.\nΧρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Δεν υποστηρίζεται η φόρτιση μέσω USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Χρήση μόνο του παρεχόμενου φορτιστή."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Ρυθμίσεις"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Έναρξη Εξοικονόμησης μπαταρίας;"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Έναρξη"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Έναρξη Εξοικονόμησης μπαταρίας"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Για να συμβάλει στη βελτίωση της διάρκειας ζωής της μπαταρίας, η Εξοικονόμηση μπαταρίας θα μειώσει την απόδοση της συσκευής σας.\n\nΗ Εξοικονόμηση μπαταρίας θα απενεργοποιηθεί όταν η συσκευή σας συνδεθεί για φόρτιση."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ρυθμίσεις"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Λειτουργία πτήσης"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Καμία πρόσφατη εφαρμογή"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Φόρτιση"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> για πλήρη φόρτιση"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Δεν φορτίζει"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Σύρετε αριστερά για τη φωτογραφική μηχανή"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Μέχρι να το απενεργοποιήσετε"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Επισκέπτης"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Επισκέπτης"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item>
     <item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Για μία ώρα"</item>
     <item quantity="other" msgid="5408537517529822157">"Για %d ώρες"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Η απόδοση της συσκευής μειώνεται."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Άνοιγμα ρυθμίσεων Εξοικονόμησης μπαταρίας"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index df8698c..82ee78c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No notifications"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Connect charger"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"The battery is getting low."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining. Battery saver is on."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Start battery saver?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Start"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Start battery saver"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"No recent apps"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Not charging"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Search"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
     <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"For one hour"</item>
     <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Device performance is reduced."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index df8698c..82ee78c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No notifications"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Connect charger"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"The battery is getting low."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining. Battery saver is on."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Start battery saver?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Start"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Start battery saver"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"No recent apps"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Not charging"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Search"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
     <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"For one hour"</item>
     <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Device performance is reduced."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 5ce867e..4145a29 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No hay notificaciones"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Conecta el cargador."</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Hay poca batería."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Batería baja"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Quedan <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante. El ahorro de batería está activado."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB.\nUsa sólo el cargador provisto."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Usa solo el cargador suministrado."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Configuración"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"¿Quieres iniciar el ahorro de batería?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar ahorro de batería"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reducirá el rendimiento del dispositivo.\n\nEsta función se inhabilitará cuando el dispositivo esté conectado."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"No hay aplicaciones recientes."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No se está cargando"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string>
     <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Desliza hacia la izquierda para acceder a la cámara."</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta que lo desactives"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Agregar invitado"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
     <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Rendimiento del dispositivo reducido"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configuración del ahorro de batería"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c25e5cd..b1dc302 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No tienes notificaciones"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Conecta el cargador"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Se está agotando la batería."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Nivel de batería bajo"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante. Ahorro de batería activado."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB.\nUtiliza solo el cargador proporcionado."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Utiliza solo el cargador proporcionado."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Ajustes"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"¿Iniciar ahorro de batería?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar ahorro de batería"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reducirá el rendimiento del dispositivo.\n\nEsta función estará inhabilitada cuando el dispositivo esté enchufado."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"No hay aplicaciones recientes"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No se está cargando"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Desliza el dedo hacia la izquierda para acceder a la cámara"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta apagar el dispositivo"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Añadir invitado"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
     <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Rendimiento del dispositivo reducido."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir ajustes de la función de ahorro de batería"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 21cb2f1..8aab7f3 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Teatisi pole"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Jätkuv"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Teadistused"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Ühendage laadija"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Aku hakkab tühjenema."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Aku hakkab tühjaks saama"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> on alles"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Alles: <xliff:g id="NUMBER">%d%%</xliff:g>. Akusäästja on sisse lülitatud."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB laadimist ei toetata.\nKasutage ainult tootja laadija."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Akukasutus"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB-ga laadimist ei toetata."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Kasutage ainult kaasasolevat laadijat."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Seaded"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Kas käivitada akusäästja?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Käivita"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Käivita akusäästja"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Aku tööea parandamiseks vähendab akusäästja teie seadme jõudlust.\n\nKui seade ühendatakse toiteallikaga, keelatakse akusäästja."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Seaded"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lennurežiim"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Hiljutisi rakendusi pole"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laadimine"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Täislaadimiseks kulub <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ei laadi"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -231,6 +241,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Kaamera kasutamiseks pühkige vasakule"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Kuni lülitate selle välja"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Külaline"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ külaline"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minutiks"</item>
@@ -239,4 +251,7 @@
     <item quantity="one" msgid="3480040795582254384">"Üheks tunniks"</item>
     <item quantity="other" msgid="5408537517529822157">"%d tunniks"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Seadme jõudlust on vähendatud."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ava akusäästja seaded"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index a0d1819..3595b6a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"اعلانی موجود نیست"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"در حال انجام"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلان‌ها"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"شارژر را متصل کنید"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"باتری در حال کم شدن است."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> باقیمانده است"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏شارژ USB پشتیبانی نمی‌شود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"استفاده از باتری"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"‏شارژ با USB پشتیبانی نمی‌شود."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"فقط از شارژر ارائه شده استفاده کنید."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"تنظیمات"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"ذخیره کننده باتری شروع شود؟"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"شروع"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"شروع ذخیره کننده باتری"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ذخیره کننده باتری برای کمک به بهبود عمر باتری شما، عملکرد دستگاهتان را کاهش می‌دهد.\n\nهنگامی که دستگاه شما به برق وصل است، ذخیره کننده باتری خاموش می‌شود."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"حالت هواپیما"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"هیچ برنامه جدیدی موجود نیست"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"در حال شارژ شدن"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مانده تا شارژ کامل شود"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"شارژ نمی‌شود"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string>
     <string name="description_target_search" msgid="3091587249776033139">"جستجو"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"برای دوربین انگشت را تند به سمت راست بکشید"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"تا وقتی آن را خاموش کنید"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"مهمان"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ مهمان"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item>
     <item quantity="other" msgid="6924190729213550991">"‏برای %d دقیقه"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"برای یک ساعت"</item>
     <item quantity="other" msgid="5408537517529822157">"‏برای %d ساعت"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"ذخیره کننده باتری روشن است."</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"عملکرد دستگاه کاهش یافته است."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"باز کردن تنظیمات ذخیره کننده باتری"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 0a0cdd9..19b0f17 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ei ilmoituksia"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Käynnissä olevat"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ilmoitukset"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Kytke laturi"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Akun virta on vähissä."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Akku on vähissä"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä. Virransäästö on käytössä."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-latausta ei tueta.\nKäytä laitteen mukana tullutta laturia."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Akun käyttö"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB-latausta ei tueta."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Käytä vain laitteen mukana toimitettua laturia."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Asetukset"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Käynnistetäänkö virransäästö?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Käynnistä"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Käynnistä virransäästö"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Virransäästötoiminto pidentää akun kestoa vähentämällä laitteen virrankulutusta.\n\nLaitteen kytkeminen virtalähteeseen poistaa virransäästön käytöstä."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Asetukset"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lentokonetila"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Ei viimeaikaisia sovelluksia"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ladataan"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> kunnes täynnä"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ei lataudu"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Haku"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,10 @@
     <string name="camera_hint" msgid="5241441720959174226">"Avaa kamera pyyhkäisemällä oikealle"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Kunnes poistat tämän käytöstä"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
+    <!-- no translation found for guest_nickname (8059989128963789678) -->
+    <skip />
+    <!-- no translation found for guest_new_guest (4259024453643879653) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item>
@@ -241,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Tunniksi"</item>
     <item quantity="other" msgid="5408537517529822157">"%d tunniksi"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Laitteen virrankulutusta vähennetään."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Avaa virransäästöasetukset"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c3b53b5..03ac011 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Brancher le chargeur"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est faible."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Pile faible"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Il reste : <xliff:g id="NUMBER">%d%%</xliff:g>. La fonction Économie d\'énergie est activée."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non compatible.\nVous devez utiliser le chargeur fourni."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Le chargement par USB n\'est pas pris en charge."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Utilisez uniquement le chargeur fourni."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Paramètres"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Démarrer la fonction Économie d\'énergie?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Démarrer"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Démarrer la fonction Économie d\'énergie"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pour vous aider à prolonger l\'autonomie de votre appareil, la fonction Économie d\'énergie réduit les performances de l\'appareil.\n\nElle se désactive lorsque l\'appareil est branché."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Aucune application récente"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charge en cours..."</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargée dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"N\'est pas en charge"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
     <string name="description_target_search" msgid="3091587249776033139">"Recherche"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Balayez l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
     <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Pendant une heure"</item>
     <item quantity="other" msgid="5408537517529822157">"Pendant %d heures"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Les performances de l\'appareil sont réduites."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres d\'économie d\'énergie"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index ab1f30b..fcad161 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Brancher le chargeur"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est faible."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Batterie faible"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Il reste <xliff:g id="NUMBER">%d%%</xliff:g>. L\'économiseur de batterie est activé."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non disponible.\nVous devez utiliser le chargeur fourni."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Chargeur USB non compatible."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Veuillez n\'utiliser que le chargeur fourni."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Paramètres"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Démarrer l\'économiseur de batterie ?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Démarrer"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Démarrer l\'économiseur de batterie"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pour vous aider à prolonger l\'autonomie de la batterie, les performances de l\'appareil sont réduites.\n\nL\'économiseur de batterie est désactivé lorsque l\'appareil est branché."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Aucune application récente"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"En charge"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargé dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"N\'est pas en charge"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
     <string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Balayer l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
     <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Pendant une heure"</item>
     <item quantity="other" msgid="5408537517529822157">"Pendant %d heures"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Les performances de l\'appareil sont réduites."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres de l\'économiseur de batterie"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8b1eb55b..c33c1d5 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"कोई सूचना नहीं"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ऑनगोइंग"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाएं"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"चार्जर कनेक्‍ट करें"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"बैटरी कम हो रही है."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"बैटरी कम है"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष. बैटरी सेवर चालू है."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है.\nकेवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"बैटरी उपयोग"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नहीं है."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"केवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"सेटिंग"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"बैटरी सेवर प्रारंभ करें?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"प्रारंभ करें"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"बैटरी सेवर प्रारंभ करें"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"बैटरी का जीवनकाल बेहतर बनाने में सहायता के लिए, बैटरी सेवर आपके उपकरण के प्रदर्शन को कम कर देगा.\n\nआपका उपकरण प्लग किए जाने पर बैटरी सेवर अक्षम हो जाएगा."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाई जहाज मोड"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"कोई हाल ही का ऐप्स नहीं"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हो रही है"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"पूर्ण होने में <xliff:g id="CHARGING_TIME">%s</xliff:g> शेष"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"चार्ज नहीं हो रही है"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
     <string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्‍लाइड करें."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"कैमरे के लिए बाएं स्वाइप करें"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"जब तक आप इसे बंद नहीं कर देते"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूर्ण होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> शेष)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथि"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item>
     <item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"एक घंटे के लिए"</item>
     <item quantity="other" msgid="5408537517529822157">"%d घंटे के लिए"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"बैटरी सेवर चालू है"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"उपकरण का प्रदर्शन कम हो गया है."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"बैटरी सेवर सेटिंग चालू करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 953e077..024be82 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bez obavijesti"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"U tijeku"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavijesti"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Priključite punjač"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterija će uskoro biti potrošena."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Niska razina baterije"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Preostalo je <xliff:g id="NUMBER">%d%%</xliff:g>. Štednja baterije je uključena."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nUpotrijebite samo priloženi punjač."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Iskorištenost baterije"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje putem USB-a nije podržano."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Upotrebljavajte samo priloženi punjač."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Postavke"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Želite li pokrenuti štednju baterije?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Kreni"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Pokretanje štednje baterije"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Da bi baterija trajala dulje, Štednja baterije smanjit će intenzitet rada uređaja.\n\nŠtednja baterije onemogućit će se kada je uređaj priključen."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način rada u zrakoplovu"</string>
@@ -186,8 +192,8 @@
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (broj uređaja: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth isključen"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Svjetlina"</string>
-    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatsko usmjerenje"</string>
-    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Usmjerenje je zaključano"</string>
+    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatsko izmjenjivanje"</string>
+    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Izmjenjivanje je zaključano"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Okomito"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Vodoravno"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Način unosa"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nema nedavnih aplikacija"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napunjenosti"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ne puni se"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Prijeđite prstom ulijevo za fotoaparat"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ gost"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item>
     <item quantity="other" msgid="6924190729213550991">"%d min"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Jedan sat"</item>
     <item quantity="other" msgid="5408537517529822157">"%d h"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Uređaj radi smanjenim intenzitetom."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvaranje postavki štednje baterije"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ad2bc5c..deeb7f4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nincs értesítés"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Folyamatban van"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Értesítések"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Csatlakoztassa a töltőt"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Az akkufeszültség alacsony."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Alacsony az energiaszint"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt. Az Akkumulátorkímélő mód bekapcsol."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Az USB-n keresztüli töltés nincs támogatva.\nHasználja a kapott töltőt."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Akkumulátorhasználat"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Az USB-n keresztüli töltés nem támogatott."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Kizárólag a tartozékként kapott töltőt használja."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Beállítások"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Elindítja az Akkumulátorkímélő módot?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Indítás"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Akkumulátorkímélő mód indítása"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Az Akkumulátorkímélő mód csökkenti az eszköz teljesítményét, hogy növelje az akkumulátor üzemidejét.\n\nAz eszköz töltésekor az Akkumulátorkímélő üzemmód kikapcsol."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Beállítások"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Repülőgép üzemmód"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nincsenek nemrég használt alkalmazások"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Töltés"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> a teljes töltöttségig"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nem töltődik"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Keresés"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"A fényképezőgép eléréséhez csúsztassa ujját balra"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Amíg ki nem kapcsolja ezt"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Vendég"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ vendég"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Egy percen át"</item>
     <item quantity="other" msgid="6924190729213550991">"%d percen át"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Egy órán át"</item>
     <item quantity="other" msgid="5408537517529822157">"%d órán át"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Az eszköz teljesítménye lecsökkentve."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Akkumulátorkímélő mód beállításainak megnyitása"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index e15730e..4424338 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Միացրեք լիցքավորիչը"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Մարտկոցը լիցքաթափվում է:"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"մնում է <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Մնաց <xliff:g id="NUMBER">%d%%</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Մարտկոցի օգտագործումը"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB լիցքավորումը չի աջակցվում:"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Օգտագործեք միայն մատակարարի տրամադրած լիցքավորիչը:"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Կարգավորումներ"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Գործարկե՞լ մարտկոցի տնտեսումը:"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Մեկնարկել"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Գործարկել մարտկոցի տնտեսումը"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Մարտկոցի տնտեսումը կնվազեցնի ձեր սարքի կատարողականը՝ մարտկոցն ավելի երկար օգտագործելու համար:\n\nՄարտկոցի տնտեսումը կանջատվի, հենց սարքը միացնեք հոսանքի աղբյուրին:"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Կարգավորումներ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Ինքնաթիռային ռեժիմ"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Նոր հավելվածներ չկան"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Լիցքավորվում է"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Լրիվ լիցքավորմանը մնաց <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Չի լիցքավորվում"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Խցիկի համար սահեցրեք ձախ"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Քանի դեռ չեք անջատել"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Հյուր"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Հյուր"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item>
     <item quantity="other" msgid="6924190729213550991">"%d րոպե"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Մեկ ժամ"</item>
     <item quantity="other" msgid="5408537517529822157">"%d ժամ"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Սարքի կատարողականը նվազեցված է:"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Բացել մարտկոցի տնտեսման կարգավորումները"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 08da900..5dbd490 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tidak ada pemberitahuan"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Berkelanjutan"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Hubungkan pengisi daya"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterai semakin lemah."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Baterai lemah"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tersisa"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Tersisa <xliff:g id="NUMBER">%d%%</xliff:g>. Penghemat baterai aktif."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Pengisian daya USB tidak didukung.\nGunakan hanya pengisi daya yang disediakan."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Penggunaan baterai"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Pengisian daya USB tidak didukung."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Hanya gunakan pengisi daya yang disediakan."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Setelan"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Mulai penghemat baterai?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Mulai"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Mulai penghemat baterai"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Untuk membantu meningkatkan masa pakai baterai, Penghemat baterai akan mengurangi kinerja perangkat Anda.\n\nPenghemat baterai akan dinonaktifkan saat perangkat dihubungkan dengan sumber daya."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setelan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode pesawat"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Tidak ada aplikasi terkini"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengisi daya"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sampai penuh"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengisi daya"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Gesek ke kiri untuk kamera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Tamu"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Tamu"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item>
     <item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
     <item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Kinerja perangkat dikurangi."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka setelan penghemat baterai"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 16ebe4c..9f1722d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nessuna notifica"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Collega il caricabatterie"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteria quasi scarica."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Batteria quasi scarica"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente. La funzione Risparmio batteria è attiva."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ricarica tramite USB non supportata.\nUtilizza solo il caricatore in dotazione."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Utilizzo batteria"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Ricarica tramite USB non supportata."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizza solo il caricabatterie fornito in dotazione."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Impostazioni"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Avviare risparmio batteria?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Inizia"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Avvia risparmio batteria"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Per aumentare la durata della batteria, Risparmio batteria riduce le prestazioni del tuo dispositivo.\n\nRisparmio batteria si disattiva quando il dispositivo è collegato alla corrente."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Impostazioni"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modalità aereo"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nessuna app recente"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"In carica"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> al termine della carica"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Non in carica"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Scorri verso sinistra per accedere alla fotocamera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Ospite"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ ospite"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Per un minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Per un\'ora"</item>
     <item quantity="other" msgid="5408537517529822157">"Per %d ore"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Le prestazioni del dispositivo sono ridotte."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Apri impostazioni risparmio batteria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 49d7b40..5b68451 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"אין התראות"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"מתמשך"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"חבר מטען"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"הסוללה נחלשת."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"עוצמת הסוללה נמוכה"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>. תכונת \'חיסכון בסוללה\' פועלת."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏טעינה באמצעות USB אינה נתמכת.\nהשתמש אך ורק במטען שסופק."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"צריכת סוללה"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"‏טעינה בחיבור USB אינה נתמכת."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"השתמש רק במטען שסופק."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"הגדרות"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"האם להפעיל את \'חיסכון בסוללה\'?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"התחל"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"הפעל את \'חיסכון בסוללה\'"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"כדי לעזור בהארכת חיי הסוללה, תכונת \'חיסכון בסוללה\' תצמצם את פעילות המכשיר.\n\nתכונת \'חיסכון בסוללה\' תושבת כשהמכשיר יחובר לחשמל."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"הגדרות"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"מצב טיסה"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"אין אפליקציות אחרונות"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"טוען"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> עד למילוי"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"לא בטעינה"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string>
     <string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"החלק שמאלה להפעלת המצלמה"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"עד שתכבה"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"אורח"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ אורח"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item>
     <item quantity="other" msgid="6924190729213550991">"‏למשך %d דקות"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"למשך שעה אחת"</item>
     <item quantity="other" msgid="5408537517529822157">"‏למשך %d שעות"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"תכונת \'חיסכון בסוללה\' פועלת"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"פעילות המכשיר צומצמה."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"פתח את ההגדרות של \'חיסכון בסוללה\'"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4a2a3c1..6ebd5c7 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"通知なし"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"充電してください"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"電池が残り少なくなっています。"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"電池残量が少なくなっています"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"残り<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"残量が<xliff:g id="NUMBER">%d%%</xliff:g>です。バッテリーセーバーはONです。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。\n付属の充電器をお使いください。"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB充電には対応していません。"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"専用の充電器のみを使用してください。"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"バッテリーセーバーを開始しますか?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"開始"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"バッテリーセーバーを開始"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを制限します。\n\n端末が電源に接続されているときはバッテリーセーバーが無効になります。"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"機内モード"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"最近使ったアプリはありません"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電しています"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"充電完了まで<xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"充電していません"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string>
     <string name="description_target_search" msgid="3091587249776033139">"検索します"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"左にスワイプしてカメラを表示"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フルになるまで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ ゲスト"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1分"</item>
     <item quantity="other" msgid="6924190729213550991">"%d分"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"1時間"</item>
     <item quantity="other" msgid="5408537517529822157">"%d時間"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"端末のパフォーマンスが制限されています。"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"バッテリーセーバーの設定を開く"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 079fc7f..8f1f30a 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"შეტყობინებები არ არის."</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"მიმდინარე"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"შეაერთეთ დამტენი."</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"ბატარეა ჯდება."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"ბატარეა იწურება"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>. გააქტიურებულია ბატარეის დამზოგი."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"ელემენტის გამოყენება"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB დატენვა მხარდაჭერილი არ არის."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"გამოიყენეთ მხოლოდ მოყოლილი დამტენი."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"პარამეტრები"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"გსურთ ბატარეის დამზოგის დაწყება?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"დაწყება"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"ბატარეის დამზოგის დაწყება"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ბატარეის მოქმედების გასახანგრძლივებლად, ბატარეის დამზოგი შეამცირებს თქვენი მოწყობილობის წარმადობას.\n\nბატარეის დამზოგი გამოირთვება, როდესაც მოწყობილობას ელკვებაზე მიაერთებთ."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"პარამეტრები"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"თვითმფრინავის რეჟიმი"</string>
@@ -120,7 +126,7 @@
     <string name="accessibility_desc_on" msgid="2385254693624345265">"ჩართული"</string>
     <string name="accessibility_desc_off" msgid="6475508157786853157">"გამორთულია."</string>
     <string name="accessibility_desc_connected" msgid="8366256693719499665">"დაკავშირებულია."</string>
-    <string name="accessibility_desc_connecting" msgid="3812924520316280149">"უკავშრდება."</string>
+    <string name="accessibility_desc_connecting" msgid="3812924520316280149">"უკავშირდება."</string>
     <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
     <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
     <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"ბოლო აპები არ არის"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"მიმდინარეობს დატენვა"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> სრულად დატენვამდე"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"არ იტენება"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"კამერისთვის მარცხენა შენაცვლება"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"სანამ ამას გამორთავდეთ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"სტუმარი"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ სტუმარი"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item>
     <item quantity="other" msgid="6924190729213550991">"%d წუთით"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"ერთი საათით"</item>
     <item quantity="other" msgid="5408537517529822157">"%d საათით"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"მოწყობილობის წარმადობა შემცირებულია."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ბატარეის დამზოგის პარამეტრების გახსნა"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index be41e50..88d9b64 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"គ្មាន​ការ​ជូន​ដំណឹង"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"បន្ត"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ការ​ជូន​ដំណឹង"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"ភ្ជាប់​ឧបករណ៍​បញ្ចូល​ថ្ម"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"ជិត​អស់​ថ្ម​ហើយ។"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"ជិត​អស់​ថ្ម​ហើយ"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"នៅ​សល់ <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"នៅ​សល់ <xliff:g id="NUMBER">%d%%</xliff:g> ។ កម្មវិធី​សន្សំ​ថ្ម​គឺ​បើក។"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"មិន​គាំទ្រ​ការ​បញ្ចូល​តាម​យូអេសប៊ី។\nប្រើ​តែ​ឧបករណ៍​បញ្ចូល​ថ្ម​ដែល​បាន​ផ្ដល់។"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"ការ​ប្រើ​ថ្ម"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"មិន​គាំទ្រ​ការ​បញ្ចូល​ថ្ម​តាម​យូអេសប៊ី​ទេ។"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"ប្រើ​តែ​ឧបករណ៍​បញ្ចូល​ថ្ម​ដែល​បាន​ផ្ដល់​ឲ្យ។"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"ការកំណត់"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"ចាប់ផ្ដើម​កម្មវិធី​សន្សំ​ថ្ម?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ចាប់ផ្ដើម"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"ចាប់ផ្ដើម​កម្មវិធី​សន្សំ​ថ្ម"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ដើម្បី​ជួយ​បង្កើន​អាយុកាល​ថ្ម កម្មវិធី​សន្សំ​ថ្ម​នឹង​កាត់បន្ថយ​ការ​អនុវត្ត​​នៃ​ឧបករណ៍​របស់​អ្នក។\n\nកម្មវិធី​សន្សំ​ថ្ម​នឹង​បិទ​នៅ​ពេល​ឧបករណ៍​របស់​អ្នក​ត្រូវ​បាន​ដោត​បញ្ចូល​ថ្ម។"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ការ​កំណត់"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"វ៉ាយហ្វាយ"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ពេល​ជិះ​យន្តហោះ"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"មិនមាន​​កម្មវិធី​ថ្មីៗ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"បាន​បញ្ចូល​ថ្ម​​"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"កំពុង​បញ្ចូល​ថ្ម"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> រហូត​ដល់ពេញ"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"មិន​កំពុង​បញ្ចូល​ថ្ម"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញ​អាច​\nត្រូវ​បាន​ត្រួតពិនិត្យ​"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"រុញ​ឡើង​លើ​ដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"អូស​ទៅ​ឆ្វេង​​ដើម្បី​ប្រើ​​ម៉ាស៊ីន​ថត"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"រហូត​ដល់ពេល​​អ្នក​បិទ​វា"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"ភ្ញៀវ"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ ភ្ញៀវ"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"សម្រាប់​មួយ​នាទី"</item>
     <item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"សម្រាប់​មួយ​ម៉ោង"</item>
     <item quantity="other" msgid="5408537517529822157">"សម្រាប់ %d ម៉ោង"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"កម្មវិធី​សន្សំ​ថ្ម​គឺ​បើក"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"ការ​អនុវត្ត​ឧបករណ៍​ត្រូវ​បាន​កាត់​បន្ថយ។"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"បើក​ការ​កំណត់​កម្មវិធី​សន្សំ​ថ្ម"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5fdc4e1..0ffb4b8 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -32,11 +32,19 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 없음"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"충전기를 연결하세요."</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"배터리가 얼마 남지 않았습니다."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"배터리 부족"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> 남음"</string>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
+    <skip />
     <string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다.\n제공된 충전기만 사용하세요."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB 충전은 지원되지 않습니다."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"제공된 충전기만 사용하세요."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"설정"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"배터리 세이버를 시작할까요?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"시작"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"배터리 세이버 시작"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"배터리 세이버는 기기의 성능을 저하시켜 배터리 수명을 늘립니다.\n\n기기에 전원이 연결되면 배터리 세이버는 사용 중지됩니다."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"설정"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"비행기 모드"</string>
@@ -215,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"최근에 사용한 앱 없음"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"충전 중"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"완충까지 <xliff:g id="CHARGING_TIME">%s</xliff:g> 남음"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"충전 안함"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string>
     <string name="description_target_search" msgid="3091587249776033139">"검색"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string>
@@ -233,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"카메라를 사용하려면 왼쪽으로 스와이프하세요."</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"손님"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"새 손님 추가"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1분 동안"</item>
     <item quantity="other" msgid="6924190729213550991">"%d분 동안"</item>
@@ -241,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"1시간 동안"</item>
     <item quantity="other" msgid="5408537517529822157">"%d시간 동안"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"배터리 세이버 사용 중"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"기기의 성능이 저하됩니다."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"배터리 세이버 설정 열기"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index abcab9e..3688c57 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ດຳເນີນຢູ່"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ການແຈ້ງເຕືອນ"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"ເຊື່ອມຕໍ່ສາຍສາກ"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"ແບັດເຕີຣີເຫຼືອໜ້ອຍແລ້ວ."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"ແບັດເຕີຣີ​ເຫຼືອ​ໜ້ອຍ"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"ຍັງເຫຼືອອີກ <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"ຍັງເຫຼືອ <xliff:g id="NUMBER">%d%%</xliff:g>. ເປີດ​ນຳໃຊ້​ໂຕປະຢັດ​ແບັດເຕີຣີ​ຢູ່."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"ບໍ່ຮອງຮັບການສາກໄຟດ້ວຍ USB.\nຕ້ອງໃຊ້ສະເພາະເຄື່ອງສາກທີ່ແຖມມານຳເທົ່ານັ້ນ."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"ການນຳໃຊ້ແບັດເຕີຣີ"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"ບໍ່​ຮອງຮັບ​ການ​ສາກ​ຜ່ານ USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"ໃຊ້​ສະເພາະ​ສາຍ​ສາກ​ທີ່​ມາ​ກັບ​ເຄື່ອງ."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"​ການ​ຕັ້ງ​ຄ່າ"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"ເລີ່ມ​ໂຕປະຢັດ​ແບັດເຕີຣີ​ບໍ?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ເລີ່ມ"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"ເລີ່ມ​ໂຕ​ປະຢັດ​ແບັດເຕີຣີ"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ເພື່ອ​ຊ່ວຍ​ຢືດ​ອາຍຸ​ແບັດເຕີຣີ, ໂຕ​ປະຢັດ​ແບັດເຕີຣີ​ຈະ​ຫຼຸດ​ປະສິດທິພາບ​ຂອງ​ອຸປະກອນ​ທ່ານ​ລົງ.\n\nໂຕ​ປະຢັດ​ແບັດເຕີຣີ​ຈະ​ຖືກ​ປິດ​ການນຳໃຊ້​ໂດຍ​ອັດຕະໂນມັດ​ເມື່ອ​ທ່ານ​ສຽບ​ສາຍ​ສາກ​ອຸປະກອນ​ຂອງ​ທ່ານ."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ການຕັ້ງຄ່າ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ໂໝດເທິງຍົນ"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"ບໍ່​ມີ​ແອັບຯ​ທີ່​ຫາ​ກໍ​ໃຊ້"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"ກຳລັງສາກໄຟ"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ຈຶ່ງ​ຈະ​ເຕັມ"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ບໍ່ໄດ້ສາກໄຟ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"ປັດ​ຊ້າຍ​ເພື່ອ​ໃຊ້​ກ້ອງ"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າ​ທ່ານ​ຈະ​ປິດ​"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"ແຂກ"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ ແຂກ"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"ເປັນ​ເວລາ​ນຶ່ງ​ນາ​ທີ"</item>
     <item quantity="other" msgid="6924190729213550991">"ເປັນ​ເວລາ %d ນາ​ທີ"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"ເປັນ​ເວລາ​ນຶ່ງ​ຊົ່ວ​ໂມງ"</item>
     <item quantity="other" msgid="5408537517529822157">"ເປັນ​ເວລາ %d ຊົ່ວ​ໂມງ"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດ​ໃຊ້​ໂຕ​ປະຢັດ​ແບັດເຕີຣີ​ແລ້ວ"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"ປະສິດທິພາບ​ຂອງ​ອຸປະກອນ​ຖືກ​ຫຼຸດ​ລົງ​ແລ້ວ."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ເປີດ​ການ​ຕັ້ງຄ່າ​ໂຕ​ປະຢັດ​ແບັດເຕີຣີ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 4818a1f..cc1ac06 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nėra įspėjimų"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Vykstantys"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Įspėjimai"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Prijunkite įkroviklį"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumuliatorius senka."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Akumuliatorius senka"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>. Akumuliatoriaus tausojimo priemonė įjungta."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB krovimas nepalaikomas.\nNaudokite tik pateiktą įkroviklį."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Akumuliatoriaus naudojimas"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB įkrovimas nepalaikomas."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Naudokite tik pateiktą kroviklį."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Nustatymai"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Paleisti akumuliatoriaus tausojimo priemonę?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Paleisti"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Paleisti akumuliatoriaus tausojimo priemonę"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Kad padėtų pailginti akumuliatoriaus naudojimo trukmę, akumuliatoriaus tausojimo priemonė sumažins įrenginio našumą.\n\nAkumuliatoriaus tausojimo priemonė bus išjungta, kai įrenginys bus prijungtas prie maitinimo šaltinio."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nustatymai"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lėktuvo režimas"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nėra naujausių programų"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kraunamas"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> iki visiško įkrovimo"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Neįkraunamas"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Perbraukite į kairę, kad būtų įjungtas fotoaparatas"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Kol išjungsite"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Svečias"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Svečias"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 min."</item>
     <item quantity="other" msgid="6924190729213550991">"%d min."</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"1 val."</item>
     <item quantity="other" msgid="5408537517529822157">"%d val."</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Įrenginio našumas sumažintas."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atidaryti akumuliatoriaus tausojimo priemonės nustatymus"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5a3a563..4e3a676 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nav paziņojumu"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Notiekošs"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Paziņojumi"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Pievienojiet uzlādes ierīci."</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumulators drīz izlādēsies."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Zems akumulatora enerģijas līmenis"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Atlicis: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Atlikuši <xliff:g id="NUMBER">%d%%</xliff:g>. Ir ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB lādēšana netiek atbalstīta.\nIzmantojiet tikai komplektā iekļauto lādētāju."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Akumulatora lietojums"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB uzlāde netiek atbalstīta."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Izmantojiet tikai komplektā iekļauto lādētāju."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Iestatījumi"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Ieslēgt"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Ieslēgt akumulatora enerģijas taupīšanas režīmu"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Lai paildzinātu akumulatora darbības laiku, akumulatora enerģijas taupīšanas režīmā tiks pazemināta ierīces veiktspēja.\n\nAkumulatora enerģijas taupīšanas režīms tiks atspējots, kad ierīce tiks pievienota uzlādes avotam."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Iestatījumi"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lidmašīnas režīms"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nav nesen izmantotu lietotņu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Notiek uzlāde"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> līdz pilnam akumulatoram"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenotiek uzlāde"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Lai lietotu kameru, velciet pa kreisi."</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Līdz brīdim, kad izslēgsiet"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Viesis"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+Viesis"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item>
     <item quantity="other" msgid="6924190729213550991">"%d min"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Vienu stundu"</item>
     <item quantity="other" msgid="5408537517529822157">"%d h"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Ierīces veiktspēja ir pazemināta."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atvērt akumulatora enerģijas taupīšanas režīma iestatījumus"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 9c02521..a2568d1 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Мэдэгдэл байхгүй"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Гарсан"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Мэдэгдэл"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Цэнэглэгчийг холбоно уу"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерей дуусаж байна."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Батерей дуусаж байна"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн. Батерей хэмнэгч асаалттай."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB цэнэглэлт дэмжигдэхгүй байна.\nЗөвхөн нийлүүлэгдсэн цэнэглэгчийг ашиглана уу."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Батерей ашиглах"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB-р цэнэглэх дэмжигддэггүй."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Зөвхөн зориулалтын ирсэн цэнэглэгч ашиглана уу."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Тохиргоо"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Батерей хэмнэгчийг эхлүүлэх үү?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Эхлэх"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Батерей хэмнэгчийг эхлүүлэх"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Батарейны ашиглалтыг уртасгахын тулд Батарей хэмнэгч нь таны төхөөрөмжийн ажиллагааг бууруулах болно.\n\nБатарей хэмнэгч нь та төхөөрөмжөө цэнэглэх үед унтарна."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Тохиргоо"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Нислэгийн горим"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Сүүлд ашигласан апп байхгүй"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Цэнэглэж байна"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"дүүргэхэд <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Цэнэглэхгүй байна"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Хайх"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Камер гаргахын тулд зүүн шударна уу"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Таныг унтраах хүртэл"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Зочин"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Зочин"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Нэг минутын турш"</item>
     <item quantity="other" msgid="6924190729213550991">"%d минутын турш"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Нэг цагийн турш"</item>
     <item quantity="other" msgid="5408537517529822157">"%d цагийн турш"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Батерей хэмнэгч асаалттай"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Төхөөрөмжийн ажиллагааг бууруулсан."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батерей хэмнэгчийн тохиргоог нээх"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 7ff19ba..7d8a1ad 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tiada pemberitahuan"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sedang berlangsung"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Sambungkan pengecas"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateri semakin lemah."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Bateri rendah"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Berbaki <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> yang tinggal. Penjimat bateri dihidupkan."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong.\nGunakan hanya pengecas yang dibekalkan."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Penggunaan bateri"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Pengecasan USB tidak disokong."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Gunakan pengecas yang dibekalkan sahaja."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Tetapan"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Hidupkan penjimat bateri?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Bermula"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Hidupkan penjimat bateri"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Untuk membantu meningkatkan hayat bateri, penjimat Bateri akan mengurangkan prestasi peranti anda.\n\nPenjimat bateri akan dilumpuhkan apabila peranti anda disambungkan kepada sumber kuasa."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod pesawat"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Tiada apl terbaharu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengecas"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Lagi <xliff:g id="CHARGING_TIME">%s</xliff:g> untuk penuh"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengecas"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,10 @@
     <string name="camera_hint" msgid="5241441720959174226">"Leret ke kiri untuk kamera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Sehingga anda matikan"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
+    <!-- no translation found for guest_nickname (8059989128963789678) -->
+    <skip />
+    <!-- no translation found for guest_new_guest (4259024453643879653) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Selama satu minit"</item>
     <item quantity="other" msgid="6924190729213550991">"Selama %d minit"</item>
@@ -241,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
     <item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Prestasi peranti dikurangkan."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka tetapan penjimat bateri"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index f0316fc..cecbe7a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Koble til lader"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Lavt batterinivå."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Batterikapasiteten er lav"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenværende"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenstår. Batterisparing er på."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke.\nBruk kun den medfølgende laderen."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Batteribruk"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Lading via USB støttes ikke."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Bruk bare den tilhørende laderen."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Innstillinger"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vil du starte batterisparing?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Start"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Start batterisparing"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"For å spare batteritid reduserer Batterisparing enhetens ytelse.\n\nBatterisparing deaktiveres når enheten er koblet til en lader."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Innstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Trådløse nettverk"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flymodus"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Ingen nylige apper"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Lader"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Fulladet om <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Lader ikke"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Sveip mot venstre for å åpne kameraet"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gjest"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Gjest"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"I ett minutt"</item>
     <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"I én time"</item>
     <item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Enhetsytelsen er redusert."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åpen innstilling for batterisparing"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 198eb8e..b6ffecf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen meldingen"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Sluit de oplader aan"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"De accu raakt leeg."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Accu is bijna leeg"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend. Accubesparing is ingeschakeld."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund.\nGebruik alleen de bijgeleverde oplader."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Accugebruik"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Opladen via USB wordt niet ondersteund."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik alleen de bijgeleverde oplader."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Instellingen"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Accubesparing starten?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Starten"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Accubesparing starten"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Om de gebruiksduur van de accu te verbeteren, beperkt Accubesparing de prestaties van uw apparaat.\n\nAccubesparing wordt uitgeschakeld wanneer uw apparaat wordt aangesloten op een stopcontact."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegmodus"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Geen recente apps"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Opladen"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot volledig opgeladen"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Wordt niet opgeladen"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Veeg naar links voor camera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat u dit uitschakelt"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Eén minuut"</item>
     <item quantity="other" msgid="6924190729213550991">"%d minuten"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Eén uur"</item>
     <item quantity="other" msgid="5408537517529822157">"%d uur"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"De prestaties van het apparaat worden beperkt."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Instellingen voor Accubesparing openen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a83c07d..05dcd82 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Brak powiadomień"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Podłącz ładowarkę"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria wkrótce się rozładuje."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Bateria jest słaba"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zostało <xliff:g id="NUMBER">%d%%</xliff:g>. Oszczędzanie baterii jest włączone."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane.\nNależy używać tylko dołączonej ładowarki."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Użycie baterii"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Ładowanie przez USB nie jest obsługiwane."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Używaj tylko ładowarki dostarczonej z urządzeniem."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Ustawienia"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Włączyć oszczędzanie baterii?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Włącz"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Włącz oszczędzanie baterii"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Funkcja oszczędzania baterii zmniejszy szybkość działania urządzenia, by ograniczyć wykorzystanie energii.\n\nOszczędzanie baterii wyłączy się, kiedy urządzenie będzie podłączone do źródła zasilania."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ustawienia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Tryb samolotowy"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Brak ostatnio uruchomionych aplikacji"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ładuje się"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do pełnego naładowania"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nie ładuje"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Szukaj"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Przesuń w górę: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Przesuń w lewo, by przełączyć się na aparat"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Dopóki nie wyłączysz"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gość"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Dodaj gościa"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Przez minutę"</item>
     <item quantity="other" msgid="6924190729213550991">"Przez %d min"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Przez godzinę"</item>
     <item quantity="other" msgid="5408537517529822157">"Przez %d godz."</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Urządzenie działa z ograniczoną szybkością."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otwórz ustawienia oszczędzania baterii"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 560f64a..657e03f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Ligar carregador"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está a ficar fraca."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restantes. A Poupança de bateria está ligada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Carregamento USB não suportado. \nUtilize apenas o carregador fornecido."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Utilização da bateria"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento por USB não é suportado."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Utilize apenas o carregador fornecido."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Definições"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Iniciar a poupança de bateria?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar a poupança de bateria"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ajudar a aumentar a duração da bateria, a Poupança de bateria reduzirá o desempenho do seu dispositivo.\n\nA Poupança de bateria será desativada assim que o dispositivo for ligado à corrente elétrica."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Definições"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo de avião"</string>
@@ -188,8 +194,8 @@
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brilho"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotação automática"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotação bloqueada"</string>
-    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertical"</string>
-    <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horizontal"</string>
+    <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Retrato"</string>
+    <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Paisagem"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Método de Introdução"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Localização"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localização Desativada"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nenhuma aplicação recente"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"A carregar"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até ficar completa"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Não está a carregar"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Deslize rapidamente para a esquerda para aceder à câmara"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Durante uma hora"</item>
     <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"O desempenho do dispositivo é reduzido."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir as definições de poupança de bateria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9dcb25da..bcf7431 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Conecte o carregador"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está ficando baixa."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante(s). A Economia de bateria está ativada."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado.\nUse apenas o carregador fornecido."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Uso da bateria"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento via USB não é suportado."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Use apenas o carregador fornecido."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Iniciar a economia de bateria?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar economia de bateria"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ajudar a melhorar a vida útil da bateria, a Economia de bateria reduzirá o desempenho do dispositivo.\n\nA Economia de bateria será desativada quando o dispositivo estiver carregando."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avião"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nenhum app recente"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do aplicativo"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Carregando"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Não está carregando"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Deslize para a esquerda para usar a câmera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ convidado"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Por 1 hora"</item>
     <item quantity="other" msgid="5408537517529822157">"Por %d horas"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"O desempenho do dispositivo foi reduzido."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configurações de economia de bateria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 73c0cd2..689aaff 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -35,15 +35,28 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nagins avis"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actual"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Avis"</string>
-    <!-- no translation found for battery_low_title (2783104807551211639) -->
-    <skip />
-    <!-- no translation found for battery_low_subtitle (1752040062087829196) -->
+    <!-- no translation found for battery_low_title (6456385927409742437) -->
     <skip />
     <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
     <skip />
+    <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
+    <skip />
     <!-- no translation found for invalid_charger (4549105996740522523) -->
     <skip />
-    <string name="battery_low_why" msgid="7279169609518386372">"Consum dad accu"</string>
+    <!-- no translation found for invalid_charger_title (3515740382572798460) -->
+    <skip />
+    <!-- no translation found for invalid_charger_text (5474997287953892710) -->
+    <skip />
+    <!-- no translation found for battery_low_why (4553600287639198111) -->
+    <skip />
+    <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
+    <skip />
+    <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
+    <skip />
+    <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
+    <skip />
+    <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
+    <skip />
     <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
     <skip />
     <!-- no translation found for status_bar_settings_wifi_button (1733928151698311923) -->
@@ -400,6 +413,14 @@
     <skip />
     <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
     <skip />
+    <!-- no translation found for expanded_header_battery_charged (5945855970267657951) -->
+    <skip />
+    <!-- no translation found for expanded_header_battery_charging (205623198487189724) -->
+    <skip />
+    <!-- no translation found for expanded_header_battery_charging_with_time (457559884275395376) -->
+    <skip />
+    <!-- no translation found for expanded_header_battery_not_charging (4798147152367049732) -->
+    <skip />
     <!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
     <skip />
     <!-- no translation found for description_target_search (3091587249776033139) -->
@@ -430,8 +451,18 @@
     <skip />
     <!-- no translation found for keyguard_indication_charging_time (1757251776872835768) -->
     <skip />
+    <!-- no translation found for guest_nickname (8059989128963789678) -->
+    <skip />
+    <!-- no translation found for guest_new_guest (4259024453643879653) -->
+    <skip />
     <!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
     <!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
     <!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
     <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
+    <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
+    <skip />
+    <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
+    <skip />
+    <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 6f992e4..c099dd9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nicio notificare"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"În desfăşurare"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Conectaţi încărcătorul"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria este descărcată."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Rămas: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Procent rămas din baterie: <xliff:g id="NUMBER">%d%%</xliff:g>. Economisirea bateriei este activată."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizaţi numai încărcătorul furnizat."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Utilizarea bateriei"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Setări"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Porniți economisirea bateriei?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Începeți"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Porniți economisirea bateriei"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pentru a mări autonomia bateriei, funcția Economisirea bateriei reduce performanța dispozitivului.\n\nEconomisirea bateriei se dezactivează când dispozitivul este conectat la priză."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod Avion"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Nicio aplicație recentă"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"S-a încărcat"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Se încarcă"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> până la încărcare completă"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nu se încarcă"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,10 @@
     <string name="camera_hint" msgid="5241441720959174226">"Glisați la stânga pentru a accesa camera foto"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Până la dezactivare"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
+    <!-- no translation found for guest_nickname (8059989128963789678) -->
+    <skip />
+    <!-- no translation found for guest_new_guest (4259024453643879653) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Timp de un minut"</item>
     <item quantity="other" msgid="6924190729213550991">"Timp de %d (de) minute"</item>
@@ -241,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Timp de o oră"</item>
     <item quantity="other" msgid="5408537517529822157">"Timp de %d (de) ore"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Performanța dispozitivului s-a redus."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Deschideți setările pentru economisirea bateriei"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 12232c5..8c59e05 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нет уведомлений"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Подключите зарядное устройство"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Батарея почти разряжена"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Уровень заряда батареи: <xliff:g id="NUMBER">%d%%</xliff:g>. Включен режим энергосбережения."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается.\nИспользуйте только зарядное устройство из комплекта поставки."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Подробнее"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Зарядка через USB не поддерживается."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Используйте только зарядное устройство, поставляемое в комплекте с устройством."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Настройки"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Включить режим энергосбережения?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ОК"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Включить режим энергосбережения"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Для экономии заряда батареи производительность устройства будет снижена.\n\nКогда устройство заряжается, режим энергосбережения отключен."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим полета"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Ничего не найдено."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядка батареи"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до полной зарядки"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не заряжается"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Поиск"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Чтобы включить камеру, пролистните влево"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Гость"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Добавить гостя"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 мин."</item>
     <item quantity="other" msgid="6924190729213550991">"%d мин."</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"1 ч."</item>
     <item quantity="other" msgid="5408537517529822157">"%d ч."</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Включен режим энергосбережения"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Производительность устройства снижена."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Открыть настройки режима энергосбережения"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index e5e0802..9456ebd 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žiadne upozornenia"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Prebiehajúce"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Pripojte nabíjačku"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Batéria je skoro vybitá."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Batéria je takmer vybitá"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>. Šetrič batérie je zapnutý."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované.\nPoužívajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Využitie batérie"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Používajte iba originálnu nabíjačku."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Nastavenia"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Chcete spustiť šetrič batérie?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Spustiť"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Spustiť šetrič batérie"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Šetrič batérie zníži výkonnosť vášho zariadenia, aby tak predĺžil výdrž batérie.\n\nPo pripojení zariadenia do zásuvky sa šetrič batérie deaktivuje."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V lietadle"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Žiadne nedávne aplikácie"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíja sa"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Úplné nabitie o <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenabíja sa"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Vyhľadávanie"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Prejdite prstom nahor: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otvoríte prejdením prstom doľava"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Hosť"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Pridať hosťa"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Na jednu minútu"</item>
     <item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"Na jednu hodinu"</item>
     <item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Výkonnosť zariadenia sa znížila."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvorte nastavenia šetriča batérie"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8fbd70d..10ba09f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ni obvestil"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Trenutno"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obvestila"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Priključite polnilnik"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterija je skoraj prazna."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Akumulator je skoraj izpraznjen"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Še <xliff:g id="NUMBER">%d%%</xliff:g>. Varčevanje z energijo akumulatorja je vklopljeno."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Polnjenje po povezavi USB ni podprto.\nUporabite priloženi polnilnik."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Uporaba baterije"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Polnjenje prek USB-ja ni podprto."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Uporabljajte samo priloženi polnilnik."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Nastavitve"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Želite zagnati varčevanje z energijo akumulatorja?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Začni"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Zaženi varčevanje z energijo akumulatorja"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Zaradi podaljšanja delovanja akumulatorja funkcija Varčevanje z energijo akumulatorja zmanjša zmogljivost delovanja naprave.\n\nVarčevanje z energijo akumulatorja se onemogoči, ko je naprava priklopljena na zunanje napajanje."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način za letalo"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Ni nedavnih aplikacij"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Polnjenje"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napolnjenosti"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Se ne polni"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Povlecite v levo za fotoaparat"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Dodajanje gosta"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Za %d min"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Za eno uro"</item>
     <item quantity="other" msgid="5408537517529822157">"Za %d h"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Zmogljivost delovanja naprave je zmanjšana."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Odpri nastavitve varčevanja z energijo akumulatorja"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index db8e278..3bee434 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нема обавештења"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текуће"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Обавештења"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Прикључите пуњач"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерија ће се ускоро испразнити."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Ниво напуњености батерије је низак"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"преостало је <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Преостало је још <xliff:g id="NUMBER">%d%%</xliff:g>. Штедња батерије је укључена."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано.\nКористите само приложени пуњач."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Коришћење батерије"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Пуњење преко USB-а није подржано."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Користите само пуњач који сте добили."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Подешавања"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Желите ли да покренете Штедњу батерије?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Покрени"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Покрените Штедњу батерије"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Да би продужила век трајања батерије, Штедња батерије ће умањити перформансе уређаја.\n\nШтедња батерије ће се искључити када укључите уређај."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подешавања"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим рада у авиону"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Нема недавних апликација"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуњење"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> док се не напуни"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не пуни се"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Превуците улево за камеру"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Гост"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Један минут"</item>
     <item quantity="other" msgid="6924190729213550991">"%d мин"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Један сат"</item>
     <item quantity="other" msgid="5408537517529822157">"%d с"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Штедња батерије је укључена"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Перформансе уређаја су умањене."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отворите подешавања Штедње батерије"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f92a4f7..b802a48 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Inga aviseringar"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Anslut laddaren"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet håller på att ta slut."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Lågt batteri"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> återstår"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> kvar. Batterisparläget har aktiverats."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB.\nAnvänd endast den laddare som levererades med telefonen."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Batteriförbrukning"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Det finns inget stöd för laddning via USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Använd endast den medföljande laddaren."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Inställningar"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vill du aktivera batterisparläget?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Börja"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Aktivera batterisparläget"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Med batterisparläget minskas enhetens prestanda i syfte att förlänga batteritiden.\n\nBatterisparläget inaktiveras när enheten ansluts till ett uttag."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Inställningar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flygplansläge"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Inga aktiva appar"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laddar"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tills batteriet är fulladdat"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Laddar inte"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Dra åt vänster om du vill visa kameran"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Tills du inaktiverar detta"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Gäst"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Lägg till gäst"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"I en minut"</item>
     <item quantity="other" msgid="6924190729213550991">"I %d minuter"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"I en timme"</item>
     <item quantity="other" msgid="5408537517529822157">"I %d timmar"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Enhetens prestanda har minskats."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Öppna inställningarna för batterisparläget"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 24cd574..1cd1752 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -30,11 +30,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Hakuna arifa"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Inaendelea"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Arifa"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Unganisha chaja"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Betri inaisha."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Betri imeisha"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> zimebakia"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Imesalia <xliff:g id="NUMBER">%d%%</xliff:g>. Kiokoa betri kimewashwa."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi.\n Tumia chaka iliyopeanwa."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Utumiaji wa betri"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Kuchaji kwa kutumia USB hakutumiki."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Tumia chaja iliyonunuliwa pamoja na kifaa pekee."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Mipangilio"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Ungependa kuwasha kiokoa betri?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Anza"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Washa kiokoa betri"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Ili kusaidia kuboresha muda wa matumizi ya betri, Kiokoa betri kitapunguza utendaji wa kifaa chako.\n\nKiokoa betri kitazimwa kifaa chako kitakapochomekwa kwenye nishati ya umeme."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mipangilio"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Mtandao-Hewa"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Hali ya Ndege"</string>
@@ -213,6 +219,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Hakuna programu za karibuni"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Inachaji"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hadi ijae"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Haichaji"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -231,6 +241,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Telezesha kidole kushoto ili ufikie kamera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Hadi utakapozima hili"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji ( <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hadi ijae)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Aliyealikwa"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Aliyealikwa"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Kwa dakika moja"</item>
     <item quantity="other" msgid="6924190729213550991">"Kwa dakika %d"</item>
@@ -239,4 +251,7 @@
     <item quantity="one" msgid="3480040795582254384">"Kwa saa moja"</item>
     <item quantity="other" msgid="5408537517529822157">"Kwa saa %d"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Utendaji wa kifaa umepunguzwa."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Fungua mipangilio ya hali inayookoa betri"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
new file mode 100644
index 0000000..f9b01c8
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+         card. -->
+    <integer name="keyguard_max_notification_count">3</integer>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 326f602..5367fbc 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -23,5 +23,8 @@
     <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item>
 
     <fraction name="keyguard_clock_y_fraction_max">37%</fraction>
-    <fraction name="keyguard_clock_y_fraction_min">14%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">20%</fraction>
+
+    <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 6dea81f..47581a9 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -28,4 +28,8 @@
 
     <!-- The number of columns that the top level tiles span in the QuickSettings -->
     <integer name="quick_settings_user_time_settings_tile_span">1</integer>
+
+    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+         card. -->
+    <integer name="keyguard_max_notification_count">5</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 313e2e8..a5e3924 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -16,8 +16,8 @@
 */
 -->
 <resources>
-    <!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
-    <dimen name="notification_panel_width">478dp</dimen>
+    <!-- The width of the notification panel window: 400 + 16 + 16 (padding in the bg drawable) -->
+    <dimen name="notification_panel_width">432dp</dimen>
 
     <!-- Gravity for the notification panel -->
     <!-- 0x31 = top|center_horizontal -->
@@ -56,10 +56,10 @@
          max value is used when no notifications are displaying, and the min value is when the
          highest possible number of notifications are showing. -->
     <fraction name="keyguard_clock_y_fraction_max">34%</fraction>
-    <fraction name="keyguard_clock_y_fraction_min">25%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">24%</fraction>
 
     <!-- The margin between the clock and the notifications on Keyguard. See
          keyguard_clock_height_fraction_* for the difference between min and max.-->
-    <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen>
-    <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_min">44dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">44dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0d6bb5c..791d5f6 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ไม่มีการแจ้งเตือน"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ดำเนินอยู่"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"การแจ้งเตือน"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"เสียบที่ชาร์จ"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"แบตเตอรี่เหลือน้อย"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"แบตเตอรี่เหลือน้อย"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"เหลืออีก <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"แบตเตอรี่เหลือ <xliff:g id="NUMBER">%d%%</xliff:g> เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB\nใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"การใช้แบตเตอรี่"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"ไม่รองรับการชาร์จผ่าน USB"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"ใช้เฉพาะที่ชาร์จที่ให้มา"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"การตั้งค่า"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"เริ่มใช้โหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"เริ่ม"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"เริ่มโหมดประหยัดแบตเตอรี่"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"เพื่อช่วยให้ใช้งานแบตเตอรี่ได้ยาวนานขึ้น โหมดประหยัดแบตเตอรี่จะลดประสิทธิภาพการทำงานของอุปกรณ์ลง\n\nโหมดประหยัดแบตเตอรี่จะปิดเมื่อคุณเสียบปลั๊กไฟกับอุปกรณ์"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"การตั้งค่า"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"โหมดใช้งานบนเครื่องบิน"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"ไม่มีแอปล่าสุด"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"กำลังชาร์จ"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จึงจะเต็ม"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ไม่ได้ชาร์จ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"กวาดไปทางซ้ายเพื่อใช้กล้องถ่ายรูป"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"จนกว่าคุณจะปิดฟังก์ชันนี้"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"ผู้เข้าร่วม"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ ผู้เข้าร่วม"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 นาที"</item>
     <item quantity="other" msgid="6924190729213550991">"%d นาที"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"1 ชั่วโมง"</item>
     <item quantity="other" msgid="5408537517529822157">"%d ชั่วโมง"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"ประสิทธิภาพการทำงานของอุปกรณ์ลดลง"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"เปิดการตั้งค่าโหมดประหยัดแบตเตอรี่"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a76eb5f..42f262b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Walang mga notification"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Nagpapatuloy"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Mga Notification"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Ikabit ang charger"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Humihina na ang baterya."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Mahina na ang baterya"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> natitira"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ang natitira. Naka-on ang tagatipid ng baterya."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Hindi sinusuportahan ang pag-charge sa USB.\nGamitin lang ang ibinigay na charger."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Paggamit ng baterya"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Hindi sinusuportahan ang pagtsa-charge gamit ang USB."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Gamitin lang ang ibinigay na charger."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Mga Setting"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Simulan ang tagatipid ng baterya?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Magsimula"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Simulan ang tagatipid ng baterya"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Upang makatulong na patagalin ang baterya, babawasan ng Tagatipid ng baterya ang pagganap ng iyong device.\n\nIdi-disable ang tagatipid ng baterya kapag naka-plug in ang iyong device."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mga Setting"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Airplane mode"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Walang kamakailang mga app"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nagcha-charge"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hanggang mapuno"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Hindi nagcha-charge"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Maghanap"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Mag-slide pataas para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Mag-swipe pakaliwa para sa camera"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Hanggang sa i-off mo ito"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Bisita"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Bisita"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Sa loob ng isang minuto"</item>
     <item quantity="other" msgid="6924190729213550991">"Sa loob ng %d (na) minuto"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Sa loob ng isang oras"</item>
     <item quantity="other" msgid="5408537517529822157">"Sa loob ng %d (na) oras"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Binawasan ang pagganap ng device."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buksan ang mga setting ng tagatipid ng baterya"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 8b37f15..7635c01 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Şarj cihazını takın"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Pil azalıyor."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Pil gücü düşük"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı. Pil tasarrufu açık."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor.\nYalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Pil kullanımı"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"USB şarjı desteklenmiyor."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Yalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Ayarlar"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Pil tasarrufu başlatılsın mı?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Başlat"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Pil tasarrufunu başlat"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pil tasarrufu, pil ömrünü iyileştirmeye yardımcı olmak için cihazınızın performansını düşürür.\n\nCihazınız fişe takılıyken Pil tasarrufu devre dışı bırakılır."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Kablosuz"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Uçak modu"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Yakın zamanda kullanılan uygulama yok"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Şarj oluyor"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Tam şarj olmasına <xliff:g id="CHARGING_TIME">%s</xliff:g> kaldı"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Şarj olmuyor"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Ara"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Kamera için sola kaydırın"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Siz bunu kapatana kadar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Misafir"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Misafir"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Bir dakika süreyle"</item>
     <item quantity="other" msgid="6924190729213550991">"%d dakika süreyle"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Bir saat süreyle"</item>
     <item quantity="other" msgid="5408537517529822157">"%d saat süreyle"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Cihazın performansı düşürüldü."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Pil tasarrufu ayarlarını aç"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 2d3609f..12dd57e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Немає сповіщень"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Поточні"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Підключіть зарядний пристрій"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Акумулятор розряджається."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Низький рівень заряду акумулятора"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>. Режим заощадження заряду акумулятора ввімкнено."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується.\nВикористовуйте лише наданий у комплекті зарядний пристрій."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Використання акумулятора"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Заряджання через USB не підтримується."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Використовуйте лише зарядний пристрій, який постачається в комплекті."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Налаштування"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Увімкнути режим заощадження заряду акумулятора?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Почати"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Увімкнути режим заощадження заряду акумулятора"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Щоб подовжити роботу акумулятора, буде знижено продуктивність пристрою.\n\nРежим заощадження заряду акумулятора вимкнеться, коли пристрій буде підключено до мережі живлення."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим польоту"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Немає останніх додатків"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Заряджається"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"До повного зарядження <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не заряджається"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Проведіть пальцем ліворуч, щоб скористатися камерою"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Доки ви не вимкнете"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Гість"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"Додати гостя"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item>
     <item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Протягом години"</item>
     <item quantity="other" msgid="5408537517529822157">"Протягом %d год"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Режим заощадження заряду акумулятора ввімкнено"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Продуктивність пристрою знижено."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Відкрийте налаштування режиму заощадження заряду акумулятора"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e15b1b5..e15d3e5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Không có thông báo nào"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Đang diễn ra"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Thông báo"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Cắm bộ sạc"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Pin đang yếu."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Pin yếu"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> còn lại"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Còn lại <xliff:g id="NUMBER">%d%%</xliff:g>. Trình tiết kiệm pin đang bật."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Không hỗ trợ sạc qua USB.\nChỉ sử dụng bộ sạc được cung cấp."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Sử dụng pin"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Sạc qua USB không được hỗ trợ."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Chỉ sử dụng bộ sạc được cung cấp."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Cài đặt"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Khởi động trình tiết kiệm pin?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Bắt đầu"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Khởi động trình tiết kiệm pin"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất của thiết bị.\n\nTrình tiết kiệm pin sẽ tắt khi thiết bị của bạn được cắm vào."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Cài đặt"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Chế độ trên máy bay"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Không có ứng dụng nào gần đây"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Đang sạc"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> cho đến khi đầy"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Hiện không sạc"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Vuốt sang trái để mở máy ảnh"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Khách"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Khách"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Trong một phút"</item>
     <item quantity="other" msgid="6924190729213550991">"Trong %d phút"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Trong một giờ"</item>
     <item quantity="other" msgid="5408537517529822157">"Trong %d giờ"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Hiệu suất của thiết bị đã giảm."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Mở cài đặt trình tiết kiệm pin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2bcd6b8..cfd4fe9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"请连接充电器"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"电池电量低。"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"还剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"电量还剩<xliff:g id="NUMBER">%d%%</xliff:g>。节电助手已启用。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支持 USB 充电功能。\n只能使用随附的充电器充电。"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电功能。"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"设置"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"启动节电助手?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"启动"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"启动节电助手"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"为了延长电池的续航时间,节电助手会减降设备的性能。\n\n设备接通电源后,节电助手会自动停用。"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飞行模式"</string>
@@ -189,7 +195,7 @@
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙:关闭"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"自动旋转"</string>
-    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"旋转功能已锁定"</string>
+    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"屏幕方向:锁定"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"纵向"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"横向"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"输入法"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"最近没有用过任何应用"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充电完成"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"正在充电"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"还需<xliff:g id="CHARGING_TIME">%s</xliff:g>才能充满"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未在充电"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string>
     <string name="description_target_search" msgid="3091587249776033139">"搜索"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -227,7 +237,7 @@
   </plurals>
     <string name="zen_mode_notification_text" msgid="8336623711388065713">"触摸即可显示"</string>
     <string name="zen_mode_title" msgid="8793432092004749188">"勿扰"</string>
-    <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+另外<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>条"</string>
+    <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"不太紧急的通知会显示在下方"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑动即可解锁"</string>
@@ -235,6 +245,10 @@
     <string name="camera_hint" msgid="5241441720959174226">"向左滑动可打开相机"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"直到您将其关闭"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
+    <!-- no translation found for guest_nickname (8059989128963789678) -->
+    <skip />
+    <!-- no translation found for guest_new_guest (4259024453643879653) -->
+    <skip />
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1分钟"</item>
     <item quantity="other" msgid="6924190729213550991">"%d分钟"</item>
@@ -243,4 +257,7 @@
     <item quantity="one" msgid="3480040795582254384">"1小时"</item>
     <item quantity="other" msgid="5408537517529822157">"%d小时"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已启用"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"设备性能已减降。"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"打开节电助手设置"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 25d9bce..4b5cf08 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"無通知"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"持續進行"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"連接充電器"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"電池即將用盡。"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"電量低"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"剩餘 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"電量剩下 <xliff:g id="NUMBER">%d%%</xliff:g>,節約電池用量模式已啟用。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"電池使用情況"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"啟動節約電池用量模式?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"開始"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"啟動節約電池用量模式"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"節約電池用量模式有助於延長電池壽命,但會降低裝置的效能。\n\n裝置接上電源時,節約電池用量模式會自動停用。"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"沒有最近使用的應用程式"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後完成充電"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"非充電中"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
     <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"向左快速滑動即可使用相機功能"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"直至您關閉這項設定"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
     <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"1 小時"</item>
     <item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"節約電池用量模式已啟用"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"裝置效能已降低。"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟節約電池用量設定"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4e4007a..a780ad1 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"沒有通知"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"連接充電器"</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"電池電量即將不足。"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"電池電力不足"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"電力剩下 <xliff:g id="NUMBER">%d%%</xliff:g>,節約耗電量模式已啟用。"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"啟動節約耗電量模式?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"啟動"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"啟動節約耗電量模式"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"節約耗電量模式有助於延長電池續航力,但會讓裝置的效能降低。\n\n裝置接上電源時,節約耗電量模式會自動停用。"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
@@ -217,6 +223,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"沒有最近使用的應用程式"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後充飽"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未充電"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string>
     <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -235,6 +245,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"向左滑動可使用相機功能"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
     <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
@@ -243,4 +255,7 @@
     <item quantity="one" msgid="3480040795582254384">"1 小時"</item>
     <item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"節約耗電量模式已啟用"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"裝置效能已降低。"</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟節約耗電量設定"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 7f292c1..8458ca8 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -32,11 +32,17 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Azikho izaziso"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Okuqhubekayo"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Izaziso"</string>
-    <string name="battery_low_title" msgid="2783104807551211639">"Xhuma ishaja."</string>
-    <string name="battery_low_subtitle" msgid="1752040062087829196">"Ibhetri iya ngokuphela."</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Ibhethri liphansi"</string>
     <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> okusele"</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> esele. Isilondolozi Sebhethri sivuliwe."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe.\nSebenzisa kuphela ishaja enikeziwe."</string>
-    <string name="battery_low_why" msgid="7279169609518386372">"Ukusebenzisa ibhetri"</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"Ukushaja kwe-USB akusekelwe."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Sebenzisa kuphela ishaja enikeziwe."</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"Izilungiselelo"</string>
+    <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Qala isilondolozi sebhethri?"</string>
+    <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Qala"</string>
+    <string name="battery_saver_start_action" msgid="7245333922937402896">"Qala isilondolozi sebhethri"</string>
+    <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Ukusiza ukuthuthukisa impilo yebhethri, Isilondolozi Sebhethri sizonciphisa ukusebenza kwedivayisi yakho.\n\nIsilondolozi Sebhethri sizokhutshazwa uma idivayisi yakho ixhunywa."</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"I-Wi-Fi"</string>
     <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Imodi yendiza"</string>
@@ -215,6 +221,10 @@
     <string name="recents_empty_message" msgid="7883614615463619450">"Azikho izinhlelo zokusebenza zakamuva"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
+    <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string>
+    <string name="expanded_header_battery_charging" msgid="205623198487189724">"Iyashaja"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ize igcwale"</string>
+    <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ayishaji"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Sesha"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -233,6 +243,8 @@
     <string name="camera_hint" msgid="5241441720959174226">"Swayiphela ngakwesokunxele ukuze uthole ikhamela"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Uze uvale lokhu"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"Isihambeli"</string>
+    <string name="guest_new_guest" msgid="4259024453643879653">"+ Isihambeli"</string>
   <plurals name="zen_mode_duration_minutes">
     <item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item>
     <item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item>
@@ -241,4 +253,7 @@
     <item quantity="one" msgid="3480040795582254384">"Ihora elilodwa"</item>
     <item quantity="other" msgid="5408537517529822157">"Amahora angu-%d"</item>
   </plurals>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
+    <string name="battery_saver_notification_text" msgid="7796554871101546872">"Ukusebenza kwedivayisi kwehlisiwe."</string>
+    <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Vula izilungiselelo zesilondolozi sebhethri"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 1ce4983..6628f3b 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -42,13 +42,11 @@
 
     <!-- BatteryMeterView parameters -->
     <array name="batterymeter_color_levels">
-        <item>4</item>
         <item>15</item>
         <item>100</item>
     </array>
     <array name="batterymeter_color_values">
         <item>#FFFF3300</item>
-        <item>#FFFF3300</item>
         <item>#FFFFFFFF</item>
     </array>
     <array name="batterymeter_bolt_points">
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index bb6f1a9..8c1a9c7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -45,18 +45,6 @@
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff686868</color>
 
-    <!-- The color of the red speed bump dot -->
-    <color name="speed_bump_dot_red">#ffd50000</color>
-
-    <!-- The color of the blue speed bump dot -->
-    <color name="speed_bump_dot_blue">#ff2962ff</color>
-
-    <!-- The color of the yellow speed bump dot -->
-    <color name="speed_bump_dot_yellow">#ffffd600</color>
-
-    <!-- The color of the green speed bump dot -->
-    <color name="speed_bump_dot_green">#ff00c853</color>
-
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#e6444444</color>
     <!-- The default recents task bar text color. -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1ef5bcd..c8851dc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -108,17 +108,25 @@
     <!-- milliseconds before the heads up notification accepts touches. -->
     <integer name="heads_up_sensitivity_delay">700</integer>
 
+    <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
+    <integer name="recents_task_bar_dismiss_delay_seconds">3</integer>
     <!-- The min animation duration for animating views that are currently visible. -->
     <integer name="recents_filter_animate_current_views_min_duration">175</integer>
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_filter_animate_new_views_min_duration">125</integer>
     <!-- The min animation duration for animating the task bar in. -->
-    <integer name="recents_animate_task_bar_enter_duration">250</integer>
+    <integer name="recents_animate_task_bar_enter_duration">275</integer>
     <!-- The animation delay for animating the first task in. This should roughly be the animation
      duration of the transition in to recents. -->
     <integer name="recents_animate_task_bar_enter_delay">225</integer>
     <!-- The min animation duration for animating the task bar out. -->
+    <integer name="recents_animate_task_exit_to_home_duration">225</integer>
+    <!-- The min animation duration for animating the task bar out. -->
     <integer name="recents_animate_task_bar_exit_duration">125</integer>
+    <!-- The min animation duration for animating the task in when transitioning from home. -->
+    <integer name="recents_animate_task_enter_from_home_duration">275</integer>
+    <!-- The animation stagger to apply to each task animation when transitioning from home. -->
+    <integer name="recents_animate_task_enter_from_home_delay">10</integer>
     <!-- The min animation duration for animating the nav bar scrim in. -->
     <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
     <!-- The animation duration for animating the removal of a task view. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 35bc7e3..8b8c126 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -235,9 +235,6 @@
     <!-- The amount of highlight to make on each task view. -->
     <dimen name="recents_task_view_highlight">1dp</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>
-
     <!-- The height of the search bar space. -->
     <dimen name="recents_search_bar_space_height">64dp</dimen>
 
@@ -275,14 +272,8 @@
     <!-- The minimum amount of top overscroll to go to the quick settings. -->
     <dimen name="min_top_overscroll_to_qs">36dp</dimen>
 
-    <!-- The height of the collapsed speed bump view. -->
-    <dimen name="speed_bump_height_collapsed">24dp</dimen>
-
-    <!-- The padding inset the explanation text needs compared to the collapsed height -->
-    <dimen name="speed_bump_text_padding_inset">10dp</dimen>
-
-    <!-- The height of the speed bump dots. -->
-    <dimen name="speed_bump_dots_height">5dp</dimen>
+    <!-- The height of the speed bump view. -->
+    <dimen name="speed_bump_height">16dp</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>
@@ -301,12 +292,12 @@
     <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
          max value is used when no notifications are displaying, and the min value is when the
          highest possible number of notifications are showing. -->
-    <fraction name="keyguard_clock_y_fraction_max">29.5%</fraction>
-    <fraction name="keyguard_clock_y_fraction_min">18%</fraction>
+    <fraction name="keyguard_clock_y_fraction_max">32.5%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">19.8%</fraction>
 
     <!-- The margin between the clock and the notifications on Keyguard. See
          keyguard_clock_height_fraction_* for the difference between min and max.-->
-    <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_min">24dp</dimen>
     <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
     <dimen name="heads_up_window_height">250dp</dimen>
 
@@ -338,4 +329,7 @@
     <!-- The width of the region on the left/right edge of the screen for performing the camera/
          phone hints. -->
     <dimen name="edge_tap_area_width">48dp</dimen>
+
+    <!-- end margin for multi user switch in expanded quick settings -->
+    <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ed32795..e5499ee 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -59,25 +59,43 @@
     <string name="status_bar_latest_events_title">Notifications</string>
 
     <!-- When the battery is low, this is displayed to the user in a dialog.  The title of the low battery alert.  [CHAR LIMIT=NONE]-->
-    <string name="battery_low_title">Connect charger</string>
-
-    <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. [CHAR LIMIT=NONE] -->
-    <string name="battery_low_subtitle">The battery is getting low.</string>
+    <string name="battery_low_title">Battery is low</string>
 
     <!-- A message that appears when the battery level is getting low in a dialog.  This is
         appened to the subtitle of the low battery alert.  "number" is the percentage of battery
         remaining [CHAR LIMIT=none]-->
     <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g> remaining</string>
 
+    <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
+    <string name="battery_low_percent_format_saver_started"><xliff:g id="number">%d%%</xliff:g> remaining. Battery saver is on.</string>
+
     <!-- A message that appears when a USB charger is plugged in and the device does not
     support charging on it.  That is, a charger that fits into the USB port and goes into
     a wall socket, not into a computer. (This happens because some devices require more
     current than the USB spec allows.  [CHAR LIMIT=NONE] -->
     <string name="invalid_charger">USB charging not supported.\nUse only the supplied charger.</string>
 
+    <!-- First line of invalid_charger, used in the notification form.  [CHAR LIMIT=NONE]-->
+    <string name="invalid_charger_title">USB charging not supported.</string>
+
+    <!-- Second line of invalid_charger, used in the notification form.  [CHAR LIMIT=NONE]-->
+    <string name="invalid_charger_text">Use only the supplied charger.</string>
+
     <!-- When the battery is low, this is the label of the button to go to the
          power usage activity to find out what drained the battery.  [CHAR LIMIT=30] -->
-    <string name="battery_low_why">Battery use</string>
+    <string name="battery_low_why">Settings</string>
+
+    <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
+    <string name="battery_saver_confirmation_title">Start battery saver?</string>
+
+    <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
+    <string name="battery_saver_confirmation_ok">Start</string>
+
+    <!-- Battery saver notification action [CHAR LIMIT=NONE]-->
+    <string name="battery_saver_start_action">Start battery saver</string>
+
+    <!-- Battery saver confirmation dialog text [CHAR LIMIT=NONE]-->
+    <string name="battery_saver_confirmation_text">To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in.</string>
 
     <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
     <string name="status_bar_settings_settings_button">Settings</string>
@@ -596,6 +614,13 @@
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
     <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
 
+    <!-- Related to user switcher --><skip/>
+    <!-- Name for the guest user -->
+    <string name="guest_nickname">Guest</string>
+
+    <!-- Label for adding a new guest -->
+    <string name="guest_new_guest">+ Guest</string>
+
     <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_minutes">
         <item quantity="one">For one minute</item>
@@ -607,4 +632,13 @@
         <item quantity="one">For one hour</item>
         <item quantity="other">For %d hours</item>
     </plurals>
+
+    <!-- Battery saver notification title. [CHAR LIMIT=60]-->
+    <string name="battery_saver_notification_title">Battery saver is on</string>
+
+    <!-- Battery saver notification text. [CHAR LIMIT=60] -->
+    <string name="battery_saver_notification_text">Device performance is reduced.</string>
+
+    <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
+    <string name="battery_saver_notification_action_text">Open battery saver settings</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 43560a3..c117eba 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -63,7 +63,7 @@
     <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
         <!-- Note: must be dp to fit in status bar -->
         <item name="android:textSize">16dp</item>
-        <item name="android:textStyle">normal</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textColor">@color/status_bar_clock_color</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 19d06be..5e48258 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -25,8 +25,6 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.os.BatteryManager;
@@ -44,7 +42,6 @@
     private static final boolean SHOW_100_PERCENT = false;
 
     private static final int FULL = 96;
-    private static final int EMPTY = 4;
 
     private static final float SUBPIXEL = 0.4f;  // inset rects for softer edges
     private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
@@ -58,6 +55,7 @@
     private int mHeight;
     private int mWidth;
     private String mWarningString;
+    private final int mCriticalLevel;
     private final int mChargeColor;
     private final float[] mBoltPoints;
     private final Path mBoltPath = new Path();
@@ -197,6 +195,8 @@
         mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
                 context.getContentResolver(), "status_bar_show_battery_percent", 0);
         mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+        mCriticalLevel = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
 
         mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mFramePaint.setColor(frameColor);
@@ -303,7 +303,7 @@
 
         if (level >= FULL) {
             drawFrac = 1f;
-        } else if (level <= EMPTY) {
+        } else if (level <= mCriticalLevel) {
             drawFrac = 0f;
         }
 
@@ -360,7 +360,7 @@
         boolean pctOpaque = false;
         float pctX = 0, pctY = 0;
         String pctText = null;
-        if (!tracker.plugged && level > EMPTY && mShowPercent
+        if (!tracker.plugged && level > mCriticalLevel && mShowPercent
                 && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
             mTextPaint.setColor(getColorForLevel(level));
             mTextPaint.setTextSize(height *
@@ -390,7 +390,7 @@
         c.drawPath(mShapePath, mBatteryPaint);
 
         if (!tracker.plugged) {
-            if (level <= EMPTY) {
+            if (level <= mCriticalLevel) {
                 // draw the warning text
                 final float x = mWidth * 0.5f;
                 final float y = (mHeight + mWarningTextHeight) * 0.48f;
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 7c85712..9650435 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -20,9 +20,14 @@
 import android.view.View;
 
 public interface RecentsComponent {
+    public interface Callbacks {
+        public void onVisibilityChanged(boolean visible);
+    }
+
     void showRecents(boolean triggeredFromAltTab, View statusBarView);
     void hideRecents(boolean triggeredFromAltTab);
     void toggleRecents(Display display, int layoutDirection, View statusBarView);
     void preloadRecents();
     void cancelPreloadingRecents();
+    void setCallback(Callbacks cb);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
index feec87c..2943494 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.power;
 
+import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -25,13 +26,13 @@
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.net.Uri;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
-import android.view.View;
+import android.view.ContextThemeWrapper;
 import android.view.WindowManager;
-import android.widget.TextView;
 
 import com.android.systemui.R;
 
@@ -46,13 +47,14 @@
     private int mBatteryLevel;
     private int mBucket;
     private long mScreenOffTime;
+    private boolean mSaver;
+    private int mSaverTriggerLevel;
 
     private AlertDialog mInvalidChargerDialog;
     private AlertDialog mLowBatteryDialog;
-    private TextView mBatteryLevelTextView;
 
     public PowerDialogWarnings(Context context) {
-        mContext = context;
+        mContext = new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light);
     }
 
     @Override
@@ -77,7 +79,7 @@
 
     @Override
     public void updateLowBatteryWarning() {
-        if (mBatteryLevelTextView != null) {
+        if (mLowBatteryDialog != null) {
             showLowBatteryWarning(false /*playSound*/);
         }
     }
@@ -93,27 +95,22 @@
     @Override
     public void showLowBatteryWarning(boolean playSound) {
         Slog.i(TAG,
-                ((mBatteryLevelTextView == null) ? "showing" : "updating")
+                ((mLowBatteryDialog == null) ? "showing" : "updating")
                 + " low battery warning: level=" + mBatteryLevel
                 + " [" + mBucket + "]");
 
-        CharSequence levelText = mContext.getString(
-                R.string.battery_low_percent_format, mBatteryLevel);
+        final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
+                : R.string.battery_low_percent_format;
+        final CharSequence levelText = mContext.getString(textRes, mBatteryLevel);
 
-        if (mBatteryLevelTextView != null) {
-            mBatteryLevelTextView.setText(levelText);
+        if (mLowBatteryDialog != null) {
+            mLowBatteryDialog.setMessage(levelText);
         } else {
-            View v = View.inflate(mContext, R.layout.battery_low, null);
-            mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent);
-
-            mBatteryLevelTextView.setText(levelText);
-
             AlertDialog.Builder b = new AlertDialog.Builder(mContext);
-                b.setCancelable(true);
-                b.setTitle(R.string.battery_low_title);
-                b.setView(v);
-                b.setIconAttribute(android.R.attr.alertDialogIcon);
-                b.setPositiveButton(android.R.string.ok, null);
+            b.setCancelable(true);
+            b.setTitle(R.string.battery_low_title);
+            b.setMessage(levelText);
+            b.setPositiveButton(android.R.string.ok, null);
 
             final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -125,6 +122,11 @@
                         new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
+                        try {
+                            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+                        } catch (RemoteException e) {
+                            // we tried
+                        }
                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                         dismissLowBatteryWarning();
                     }
@@ -136,10 +138,9 @@
                     @Override
                     public void onDismiss(DialogInterface dialog) {
                         mLowBatteryDialog = null;
-                        mBatteryLevelTextView = null;
                     }
                 });
-            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
             d.getWindow().getAttributes().privateFlags |=
                     WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
             d.show();
@@ -198,21 +199,32 @@
         dismissLowBatteryWarning();
 
         AlertDialog.Builder b = new AlertDialog.Builder(mContext);
-            b.setCancelable(true);
-            b.setMessage(R.string.invalid_charger);
-            b.setIconAttribute(android.R.attr.alertDialogIcon);
-            b.setPositiveButton(android.R.string.ok, null);
+        b.setCancelable(true);
+        b.setTitle(R.string.invalid_charger_title);
+        b.setMessage(R.string.invalid_charger_text);
+        b.setPositiveButton(android.R.string.ok, null);
 
         AlertDialog d = b.create();
             d.setOnDismissListener(new DialogInterface.OnDismissListener() {
                     public void onDismiss(DialogInterface dialog) {
                         mInvalidChargerDialog = null;
-                        mBatteryLevelTextView = null;
                     }
                 });
 
-        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+        d.getWindow().getAttributes().privateFlags |=
+                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         d.show();
         mInvalidChargerDialog = d;
     }
+
+    @Override
+    public void showSaverMode(boolean mode) {
+        mSaver = mode;
+    }
+
+    @Override
+    public void setSaverTrigger(int level) {
+        mSaverTriggerLevel = level;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
new file mode 100644
index 0000000..c3ba349
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -0,0 +1,389 @@
+/*
+ * 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.power;
+
+import android.app.AlertDialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import java.io.PrintWriter;
+
+public class PowerNotificationWarnings implements PowerUI.WarningsUI {
+    private static final String TAG = PowerUI.TAG + ".Notification";
+    private static final boolean DEBUG = PowerUI.DEBUG;
+
+    private static final String TAG_NOTIFICATION = "low_battery";
+    private static final int ID_NOTIFICATION = 100;
+    private static final int AUTO_DISMISS_MS = 10000;
+
+    private static final int SHOWING_NOTHING = 0;
+    private static final int SHOWING_WARNING = 1;
+    private static final int SHOWING_SAVER = 2;
+    private static final int SHOWING_INVALID_CHARGER = 3;
+    private static final String[] SHOWING_STRINGS = {
+        "SHOWING_NOTHING",
+        "SHOWING_WARNING",
+        "SHOWING_SAVER",
+        "SHOWING_INVALID_CHARGER",
+    };
+
+    private static final String ACTION_SHOW_FALLBACK_WARNING = "PNW.warningFallback";
+    private static final String ACTION_SHOW_FALLBACK_CHARGER = "PNW.chargerFallback";
+    private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
+    private static final String ACTION_START_SAVER = "PNW.startSaver";
+
+    private final Context mContext;
+    private final Context mLightContext;
+    private final NotificationManager mNoMan;
+    private final Handler mHandler = new Handler();
+    private final PowerDialogWarnings mFallbackDialogs;
+    private final Receiver mReceiver = new Receiver();
+    private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
+    private final Intent mOpenSaverSettings = settings(Settings.ACTION_BATTERY_SAVER_SETTINGS);
+
+    private int mBatteryLevel;
+    private int mBucket;
+    private long mScreenOffTime;
+    private int mShowing;
+
+    private boolean mSaver;
+    private int mSaverTriggerLevel;
+    private boolean mWarning;
+    private boolean mPlaySound;
+    private boolean mInvalidCharger;
+
+    public PowerNotificationWarnings(Context context) {
+        mContext = context;
+        mLightContext = new ContextThemeWrapper(mContext,
+                android.R.style.Theme_DeviceDefault_Light);
+        mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        mFallbackDialogs = new PowerDialogWarnings(context);
+        mReceiver.init();
+    }
+
+    @Override
+    public void dump(PrintWriter pw) {
+        pw.print("mSaver="); pw.println(mSaver);
+        pw.print("mWarning="); pw.println(mWarning);
+        pw.print("mPlaySound="); pw.println(mPlaySound);
+        pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
+        pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
+    }
+
+    @Override
+    public void update(int batteryLevel, int bucket, long screenOffTime) {
+        mBatteryLevel = batteryLevel;
+        mBucket = bucket;
+        mScreenOffTime = screenOffTime;
+        mFallbackDialogs.update(batteryLevel, bucket, screenOffTime);
+    }
+
+    @Override
+    public void showSaverMode(boolean mode) {
+        mSaver = mode;
+        updateNotification();
+    }
+
+    @Override
+    public void setSaverTrigger(int level) {
+        mSaverTriggerLevel = level;
+        updateNotification();
+    }
+
+    private void updateNotification() {
+        if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning
+                + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger);
+        if (mInvalidCharger) {
+            showInvalidChargerNotification();
+            mShowing = SHOWING_INVALID_CHARGER;
+        } else if (mWarning) {
+            showWarningNotification();
+            mShowing = SHOWING_WARNING;
+        } else if (mSaver) {
+            showSaverNotification();
+            mShowing = SHOWING_SAVER;
+        } else {
+            mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION);
+            mShowing = SHOWING_NOTHING;
+        }
+    }
+
+    private void showInvalidChargerNotification() {
+        final Notification.Builder nb = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_power_low)
+                .setShowWhen(false)
+                .setOngoing(true)
+                .setContentTitle(mContext.getString(R.string.invalid_charger_title))
+                .setContentText(mContext.getString(R.string.invalid_charger_text))
+                .setPriority(Notification.PRIORITY_MAX)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true);
+        final Notification n = nb.build();
+        if (n.headsUpContentView != null) {
+            n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
+        }
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+    }
+
+    private void showWarningNotification() {
+        final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
+                : R.string.battery_low_percent_format;
+        final Notification.Builder nb = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_power_low)
+                .setShowWhen(false)
+                .setContentTitle(mContext.getString(R.string.battery_low_title))
+                .setContentText(mContext.getString(textRes, mBatteryLevel))
+                .setOngoing(true)
+                .setPriority(Notification.PRIORITY_MAX)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true);
+        if (hasBatterySettings()) {
+            nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
+        }
+        if (!mSaver && mSaverTriggerLevel <= 0) {
+            nb.addAction(R.drawable.ic_power_saver,
+                    mContext.getString(R.string.battery_saver_start_action),
+                    pendingBroadcast(ACTION_START_SAVER));
+        }
+        if (mPlaySound) {
+            attachLowBatterySound(nb);
+        }
+        final Notification n = nb.build();
+        if (n.headsUpContentView != null) {
+            n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
+        }
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+    }
+
+    private void showSaverNotification() {
+        final Notification.Builder nb = new Notification.Builder(mContext)
+                .setSmallIcon(R.drawable.ic_power_saver)
+                .setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
+                .setContentText(mContext.getString(R.string.battery_saver_notification_text))
+                .setOngoing(true)
+                .setShowWhen(false)
+                .setCategory(Notification.CATEGORY_SYSTEM);
+        if (hasSaverSettings()) {
+            nb.addAction(0,
+                    mContext.getString(R.string.battery_saver_notification_action_text),
+                    pendingActivity(mOpenSaverSettings));
+            nb.setContentIntent(pendingActivity(mOpenSaverSettings));
+        }
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
+    }
+
+    private PendingIntent pendingActivity(Intent intent) {
+        return PendingIntent.getActivityAsUser(mContext,
+                0, intent, 0, null, UserHandle.CURRENT);
+    }
+
+    private PendingIntent pendingBroadcast(String action) {
+        return PendingIntent.getBroadcastAsUser(mContext,
+                0, new Intent(action), 0, UserHandle.CURRENT);
+    }
+
+    private static Intent settings(String action) {
+        return new Intent(action).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                | Intent.FLAG_ACTIVITY_NO_HISTORY
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+    }
+
+    @Override
+    public boolean isInvalidChargerWarningShowing() {
+        return mInvalidCharger;
+    }
+
+    @Override
+    public void updateLowBatteryWarning() {
+        updateNotification();
+        mFallbackDialogs.updateLowBatteryWarning();
+    }
+
+    @Override
+    public void dismissLowBatteryWarning() {
+        if (DEBUG) Slog.d(TAG, "dismissing low battery warning: level=" + mBatteryLevel);
+        dismissLowBatteryNotification();
+        mFallbackDialogs.dismissLowBatteryWarning();
+    }
+
+    private void dismissLowBatteryNotification() {
+        if (mWarning) Slog.i(TAG, "dismissing low battery notification");
+        mWarning = false;
+        updateNotification();
+    }
+
+    private boolean hasBatterySettings() {
+        return mOpenBatterySettings.resolveActivity(mContext.getPackageManager()) != null;
+    }
+
+    private boolean hasSaverSettings() {
+        return mOpenSaverSettings.resolveActivity(mContext.getPackageManager()) != null;
+    }
+
+    @Override
+    public void showLowBatteryWarning(boolean playSound) {
+        Slog.i(TAG,
+                "show low battery warning: level=" + mBatteryLevel
+                + " [" + mBucket + "]");
+        mPlaySound = playSound;
+        mWarning = true;
+        updateNotification();
+        mHandler.removeCallbacks(mDismissLowBatteryNotification);
+        mHandler.postDelayed(mDismissLowBatteryNotification, AUTO_DISMISS_MS);
+    }
+
+    private void attachLowBatterySound(Notification.Builder b) {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        final int silenceAfter = Settings.Global.getInt(cr,
+                Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0);
+        final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime;
+        if (silenceAfter > 0
+                && mScreenOffTime > 0
+                && offTime > silenceAfter) {
+            Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter
+                    + "ms): not waking up the user with low battery sound");
+            return;
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG, "playing low battery sound. pick-a-doop!"); // WOMP-WOMP is deprecated
+        }
+
+        if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) {
+            final String soundPath = Settings.Global.getString(cr,
+                    Settings.Global.LOW_BATTERY_SOUND);
+            if (soundPath != null) {
+                final Uri soundUri = Uri.parse("file://" + soundPath);
+                if (soundUri != null) {
+                    b.setSound(soundUri, AudioManager.STREAM_SYSTEM);
+                    Slog.d(TAG, "playing sound " + soundUri);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void dismissInvalidChargerWarning() {
+        dismissInvalidChargerNotification();
+        mFallbackDialogs.dismissInvalidChargerWarning();
+    }
+
+    private void dismissInvalidChargerNotification() {
+        if (mInvalidCharger) Slog.i(TAG, "dismissing invalid charger notification");
+        mInvalidCharger = false;
+        updateNotification();
+    }
+
+    @Override
+    public void showInvalidChargerWarning() {
+        mInvalidCharger = true;
+        updateNotification();
+    }
+
+    private void showStartSaverConfirmation() {
+        final AlertDialog d = new AlertDialog.Builder(mLightContext)
+                .setTitle(R.string.battery_saver_confirmation_title)
+                .setMessage(R.string.battery_saver_confirmation_text)
+                .setNegativeButton(android.R.string.cancel, null)
+                .setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode)
+                .create();
+
+        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+        d.getWindow().getAttributes().privateFlags |=
+                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        d.show();
+    }
+
+    private void setSaverSetting(boolean mode) {
+        final int val = mode ? 1 : 0;
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, val);
+    }
+
+    private final class Receiver extends BroadcastReceiver {
+
+        public void init() {
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(ACTION_SHOW_FALLBACK_WARNING);
+            filter.addAction(ACTION_SHOW_FALLBACK_CHARGER);
+            filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
+            filter.addAction(ACTION_START_SAVER);
+            mContext.registerReceiver(this, filter, null, mHandler);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            Slog.i(TAG, "Received " + action);
+            if (action.equals(ACTION_SHOW_FALLBACK_WARNING)) {
+                dismissLowBatteryNotification();
+                mFallbackDialogs.showLowBatteryWarning(false /*playSound*/);
+            } else if (action.equals(ACTION_SHOW_FALLBACK_CHARGER)) {
+                dismissInvalidChargerNotification();
+                mFallbackDialogs.showInvalidChargerWarning();
+            } else if (action.equals(ACTION_SHOW_BATTERY_SETTINGS)) {
+                dismissLowBatteryNotification();
+                mContext.startActivityAsUser(mOpenBatterySettings, UserHandle.CURRENT);
+            } else if (action.equals(ACTION_START_SAVER)) {
+                dismissLowBatteryNotification();
+                showStartSaverConfirmation();
+            }
+        }
+    }
+
+    private final OnClickListener mStartSaverMode = new OnClickListener() {
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            AsyncTask.execute(new Runnable() {
+                @Override
+                public void run() {
+                    setSaverSetting(true);
+                }
+            });
+        }
+    };
+
+    private final Runnable mDismissLowBatteryNotification = new Runnable() {
+        @Override
+        public void run() {
+            dismissLowBatteryNotification();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 0fb0f8b..1bb7edb 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -17,13 +17,17 @@
 package com.android.systemui.power;
 
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
 
@@ -35,13 +39,15 @@
 
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
-
     static final boolean DEBUG = false;
 
-    private WarningsUI mWarnings;
 
     private final Handler mHandler = new Handler();
+    private final SettingsObserver mObserver = new SettingsObserver(mHandler);
+    private final Receiver mReceiver = new Receiver();
 
+    private PowerManager mPowerManager;
+    private WarningsUI mWarnings;
     private int mBatteryLevel = 100;
     private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
     private int mPlugType = 0;
@@ -53,24 +59,54 @@
     private long mScreenOffTime = -1;
 
     public void start() {
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
+        mWarnings = new PowerNotificationWarnings(mContext);
 
-        mLowBatteryAlertCloseLevel = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
-        mLowBatteryReminderLevels[0] = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        mLowBatteryReminderLevels[1] = mContext.getResources().getInteger(
+        ContentObserver obs = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                updateBatteryWarningLevels();
+            }
+        };
+        final ContentResolver resolver = mContext.getContentResolver();
+        resolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+                false, obs, UserHandle.USER_ALL);
+        updateBatteryWarningLevels();
+        mReceiver.init();
+        mObserver.init();
+    }
+
+    private void setSaverMode(boolean mode) {
+        mWarnings.showSaverMode(mode);
+    }
+
+    private void setSaverTrigger(int level) {
+        mWarnings.setSaverTrigger(level);
+    }
+
+    void updateBatteryWarningLevels() {
+        int critLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
 
-        final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mScreenOffTime = pm.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
-        mWarnings = new PowerDialogWarnings(mContext);
+        final ContentResolver resolver = mContext.getContentResolver();
+        int defWarnLevel = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lowBatteryWarningLevel);
+        int warnLevel = Settings.Global.getInt(resolver,
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+        if (warnLevel == 0) {
+            warnLevel = defWarnLevel;
+        }
+        if (warnLevel < critLevel) {
+            warnLevel = critLevel;
+        }
 
-        // Register for Intent broadcasts for...
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Intent.ACTION_SCREEN_ON);
-        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+        mLowBatteryReminderLevels[0] = warnLevel;
+        mLowBatteryReminderLevels[1] = critLevel;
+        mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
+                + mContext.getResources().getInteger(
+                        com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
     }
 
     /**
@@ -87,7 +123,7 @@
         if (level >= mLowBatteryAlertCloseLevel) {
             return 1;
         }
-        if (level >= mLowBatteryReminderLevels[0]) {
+        if (level > mLowBatteryReminderLevels[0]) {
             return 0;
         }
         final int N = mLowBatteryReminderLevels.length;
@@ -99,7 +135,23 @@
         throw new RuntimeException("not possible!");
     }
 
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+    private final class Receiver extends BroadcastReceiver {
+
+        public void init() {
+            // Register for Intent broadcasts for...
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+            mContext.registerReceiver(this, filter, null, mHandler);
+            updateSaverMode();
+        }
+
+        private void updateSaverMode() {
+            setSaverMode(mPowerManager.isPowerSaveMode());
+        }
+
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -160,6 +212,8 @@
                 mScreenOffTime = SystemClock.elapsedRealtime();
             } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 mScreenOffTime = -1;
+            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
+                updateSaverMode();
             } else {
                 Slog.w(TAG, "unknown intent: " + intent);
             }
@@ -197,6 +251,8 @@
 
     public interface WarningsUI {
         void update(int batteryLevel, int bucket, long screenOffTime);
+        void setSaverTrigger(int level);
+        void showSaverMode(boolean mode);
         void dismissLowBatteryWarning();
         void showLowBatteryWarning(boolean playSound);
         void dismissInvalidChargerWarning();
@@ -205,5 +261,29 @@
         boolean isInvalidChargerWarningShowing();
         void dump(PrintWriter pw);
     }
+
+    private final class SettingsObserver extends ContentObserver {
+        private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI =
+                Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
+
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void init() {
+            onChange(true, LOW_POWER_MODE_TRIGGER_LEVEL_URI);
+            final ContentResolver cr = mContext.getContentResolver();
+            cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) {
+                final int level = Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+                setSaverTrigger(level);
+            }
+        }
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index c76ee8c..786cd9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -287,6 +287,7 @@
         public boolean activityIn;
         public boolean activityOut;
         public int overlayIconId;
+        public boolean filter;
 
         @Override
         public boolean copyTo(State other) {
@@ -300,6 +301,7 @@
             o.activityIn = activityIn;
             o.activityOut = activityOut;
             o.overlayIconId = overlayIconId;
+            o.filter = filter;
             return super.copyTo(other) || changed;
         }
 
@@ -311,6 +313,7 @@
             rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
             rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
             rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
+            rt.insert(rt.length() - 1, ",filter=" + filter);
             return rt;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index 901cc10..d5fe033 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -93,12 +93,12 @@
         final SignalState s = (SignalState) state;
         mSignal.setImageDrawable(null);  // force refresh
         mSignal.setImageResource(s.iconId);
-        mSignal.setColorFilter(FILTER);
+        mSignal.setColorFilter(s.filter ? FILTER : null);
         if (s.overlayIconId > 0) {
             mOverlay.setVisibility(VISIBLE);
             mOverlay.setImageDrawable(null);  // force refresh
             mOverlay.setImageResource(s.overlayIconId);
-            mOverlay.setColorFilter(FILTER);
+            mOverlay.setColorFilter(s.filter ? FILTER : null);
         } else {
             mOverlay.setVisibility(GONE);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 182a0ce..6d91d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -72,12 +72,15 @@
         if (cb == null) return;
 
         final Resources r = mContext.getResources();
-        state.iconId = cb.enabled && (cb.mobileSignalIconId > 0)
+        state.iconId = cb.noSim
+                ? R.drawable.stat_sys_no_sim
+                : cb.enabled && (cb.mobileSignalIconId > 0)
                 ? cb.mobileSignalIconId
                 : R.drawable.ic_qs_signal_no_signal;
         state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
                 ? cb.dataTypeIconId
                 : 0;
+        state.filter = state.iconId != R.drawable.stat_sys_no_sim;
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
 
@@ -117,6 +120,7 @@
         boolean activityIn;
         boolean activityOut;
         String enabledDesc;
+        boolean noSim;
     }
 
     private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
@@ -134,7 +138,7 @@
                 int mobileSignalIconId,
                 String mobileSignalContentDescriptionId, int dataTypeIconId,
                 boolean activityIn, boolean activityOut,
-                String dataTypeContentDescriptionId, String description) {
+                String dataTypeContentDescriptionId, String description, boolean noSim) {
             final CallbackInfo info = new CallbackInfo();  // TODO pool?
             info.enabled = enabled;
             info.wifiEnabled = mWifiEnabled;
@@ -145,6 +149,7 @@
             info.activityIn = activityIn;
             info.activityOut = activityOut;
             info.enabledDesc = description;
+            info.noSim = noSim;
             refreshState(info);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5301362..7c2c7c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,6 +71,6 @@
         state.visible = mVisible;
         state.value = enabled;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
-        state.iconId = R.drawable.ic_qs_color_inversion;
+        state.iconId = enabled ? R.drawable.ic_qs_inversion_on : R.drawable.ic_qs_inversion_off;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index db9b054..04f1eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.qs.tiles;
 
-import android.content.res.Resources;
-import android.graphics.drawable.AnimationDrawable;
-
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -63,28 +60,15 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean locationEnabled =  mController.isLocationEnabled();
         state.visible = true;
-        if (state.value != locationEnabled) {
-            state.value = locationEnabled;
-            final Resources res = mContext.getResources();
-            final AnimationDrawable d = (AnimationDrawable) res.getDrawable(locationEnabled
-                    ? R.drawable.ic_qs_location_on
-                    : R.drawable.ic_qs_location_off);
-            state.icon = d;
-            mUiHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    d.start();
-                }
-            });
-        }
+        state.value = locationEnabled;
         if (locationEnabled) {
-            if (state.icon == null) state.iconId = R.drawable.ic_qs_location_01;
+            state.iconId = R.drawable.ic_qs_location_on;
             state.label = mContext.getString(R.string.quick_settings_location_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location,
                     mContext.getString(R.string.accessibility_desc_on));
         } else {
-            if (state.icon == null) state.iconId = R.drawable.ic_qs_location_11;
+            state.iconId = R.drawable.ic_qs_location_off;
             state.label = mContext.getString(R.string.quick_settings_location_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
index b981ed6..c4bdb19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
@@ -69,6 +69,7 @@
 
             @Override
             public void onViewAttachedToWindow(View v) {
+                vp.updateStates();
                 volumeComponent.setVolumePanel(vp);
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 6b73002..a236497 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -87,6 +87,7 @@
         state.connected = wifiConnected;
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
+        state.filter = true;
         final String signalContentDescription;
         final Resources r = mContext.getResources();
         if (wifiConnected) {
@@ -159,7 +160,7 @@
                 int mobileSignalIconId,
                 String mobileSignalContentDescriptionId, int dataTypeIconId,
                 boolean activityIn, boolean activityOut,
-                String dataTypeContentDescriptionId, String description) {
+                String dataTypeContentDescriptionId, String description, boolean noSim) {
             // noop
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index 116d755d..e03c01c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -273,6 +273,13 @@
         }
     }
 
+    @Override
+    public void setCallback(Callbacks cb) {
+        if (mUseAlternateRecents) {
+            mAlternateRecents.setRecentsComponentCallback(cb);
+        }
+    }
+
     /**
      * Send broadcast only if BOOT_COMPLETED
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 2f6d58f..8dcdcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -27,7 +27,6 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -35,16 +34,13 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.UserHandle;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Surface;
-import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
 import com.android.systemui.R;
+import com.android.systemui.RecentsComponent;
 
+import java.lang.ref.WeakReference;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -129,8 +125,10 @@
     final public static int MSG_TOGGLE_RECENTS = 6;
     final public static int MSG_START_ENTER_ANIMATION = 7;
 
-    final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail";
-    final public static String EXTRA_FROM_ALT_TAB = "recents.triggeredFromAltTab";
+    final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
+    final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail";
+    final public static String EXTRA_FROM_APP_FULL_SCREENSHOT = "recents.thumbnail";
+    final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
     final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration";
     final public static String KEY_WINDOW_RECT = "recents.windowRect";
     final public static String KEY_SYSTEM_INSETS = "recents.systemInsets";
@@ -138,7 +136,6 @@
     final public static String KEY_TWO_TASK_STACK_RECT = "recents.twoCountTaskRect";
     final public static String KEY_MULTIPLE_TASK_STACK_RECT = "recents.multipleCountTaskRect";
 
-
     final static int sMinToggleDelay = 425;
 
     final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS";
@@ -146,6 +143,9 @@
     final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
     final static String sRecentsService = "com.android.systemui.recents.RecentsService";
 
+    static Bitmap sLastScreenshot;
+    static RecentsComponent.Callbacks sRecentsComponentCallbacks;
+
     Context mContext;
     SystemServicesProxy mSystemServicesProxy;
 
@@ -213,15 +213,19 @@
         if (Console.Enabled) {
             Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
         }
+
         if (mServiceIsBound && mBootCompleted) {
-            // Notify recents to close it
-            try {
-                Bundle data = new Bundle();
-                Message msg = Message.obtain(null, MSG_HIDE_RECENTS, triggeredFromAltTab ? 1 : 0, 0);
-                msg.setData(data);
-                mService.send(msg);
-            } catch (RemoteException re) {
-                re.printStackTrace();
+            if (isRecentsTopMost(null)) {
+                // Notify recents to close it
+                try {
+                    Bundle data = new Bundle();
+                    Message msg = Message.obtain(null, MSG_HIDE_RECENTS,
+                            triggeredFromAltTab ? 1 : 0, 0);
+                    msg.setData(data);
+                    mService.send(msg);
+                } catch (RemoteException re) {
+                    re.printStackTrace();
+                }
             }
         }
     }
@@ -283,7 +287,7 @@
 
     /** Updates each of the task animation rects. */
     void updateAnimationRects() {
-        if (mServiceIsBound && mBootCompleted) {
+        if (mServiceIsBound) {
             Resources res = mContext.getResources();
             int statusBarHeight = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.status_bar_height);
@@ -343,80 +347,6 @@
         }
     }
 
-    /** Converts from the device rotation to the degree */
-    float getDegreesForRotation(int value) {
-        switch (value) {
-            case Surface.ROTATION_90:
-                return 360f - 90f;
-            case Surface.ROTATION_180:
-                return 360f - 180f;
-            case Surface.ROTATION_270:
-                return 360f - 270f;
-        }
-        return 0f;
-    }
-
-    /** Takes a screenshot of the surface */
-    Bitmap takeScreenshot(Display display) {
-        DisplayMetrics dm = new DisplayMetrics();
-        display.getRealMetrics(dm);
-        float[] dims = {dm.widthPixels, dm.heightPixels};
-        float degrees = getDegreesForRotation(display.getRotation());
-        boolean requiresRotation = (degrees > 0);
-        if (requiresRotation) {
-            // Get the dimensions of the device in its native orientation
-            Matrix m = new Matrix();
-            m.preRotate(-degrees);
-            m.mapPoints(dims);
-            dims[0] = Math.abs(dims[0]);
-            dims[1] = Math.abs(dims[1]);
-        }
-        return SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
-    }
-
-    /** Creates the activity options for a thumbnail transition. */
-    ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
-        // Loading from thumbnail
-        Bitmap thumbnail;
-        Bitmap firstThumbnail = loadFirstTaskThumbnail();
-        if (firstThumbnail != null) {
-            // Create the thumbnail
-            thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
-                    Bitmap.Config.ARGB_8888);
-            int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
-            Canvas c = new Canvas(thumbnail);
-            c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
-                    new Rect(0, 0, taskRect.width(), taskRect.height()), null);
-            c.setBitmap(null);
-            // Recycle the old thumbnail
-            firstThumbnail.recycle();
-        } else {
-            // Load the thumbnail from the screenshot if can't get one from the system
-            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-            Display display = wm.getDefaultDisplay();
-            Bitmap screenshot = takeScreenshot(display);
-            if (screenshot != null) {
-                Resources res = mContext.getResources();
-                int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
-                int statusBarHeight = res.getDimensionPixelSize(
-                        com.android.internal.R.dimen.status_bar_height);
-                thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
-                        Bitmap.Config.ARGB_8888);
-                Canvas c = new Canvas(thumbnail);
-                c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight +
-                        size), new Rect(0, 0, taskRect.width(), taskRect.height()), null);
-                c.setBitmap(null);
-                // Recycle the temporary screenshot
-                screenshot.recycle();
-            } else {
-                return null;
-            }
-        }
-
-        return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, thumbnail,
-                taskRect.left, taskRect.top, this);
-    }
-
     /** Returns whether the recents is currently running */
     boolean isRecentsTopMost(AtomicBoolean isHomeTopMost) {
         SystemServicesProxy ssp = mSystemServicesProxy;
@@ -462,10 +392,12 @@
                 mService.send(msg);
 
                 // Time this path
-                Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                        Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
-                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                        Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
+                if (Console.Enabled) {
+                    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();
             }
@@ -486,6 +418,68 @@
         }
     }
 
+    /**
+     * Creates the activity options for a unknown state->recents transition.
+     */
+    ActivityOptions getUnknownTransitionActivityOptions() {
+        // Reset the last screenshot
+        consumeLastScreenshot();
+        return ActivityOptions.makeCustomAnimation(mContext,
+                R.anim.recents_from_unknown_enter,
+                R.anim.recents_from_unknown_exit, mHandler, this);
+    }
+
+    /**
+     * Creates the activity options for a home->recents transition.
+     */
+    ActivityOptions getHomeTransitionActivityOptions() {
+        // Reset the last screenshot
+        consumeLastScreenshot();
+        return ActivityOptions.makeCustomAnimation(mContext,
+                R.anim.recents_from_launcher_enter,
+                R.anim.recents_from_launcher_exit, mHandler, this);
+    }
+
+    /**
+     * Creates the activity options for an app->recents transition.  If this method sets the static
+     * screenshot, then we will use that for the transition.
+     */
+    ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
+        // Recycle the last screenshot
+        consumeLastScreenshot();
+
+        // Take the full screenshot
+        if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+            sLastScreenshot = mSystemServicesProxy.takeScreenshot();
+            if (sLastScreenshot != null) {
+                return ActivityOptions.makeCustomAnimation(mContext,
+                        R.anim.recents_from_app_enter,
+                        R.anim.recents_from_app_exit, mHandler, this);
+            }
+        }
+
+        // If the screenshot fails, then load the first task thumbnail and use that
+        Bitmap firstThumbnail = loadFirstTaskThumbnail();
+        if (firstThumbnail != null) {
+            // Create the new thumbnail for the animation down
+            // XXX: We should find a way to optimize this so we don't need to create a new bitmap
+            Bitmap thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+                    Bitmap.Config.ARGB_8888);
+            int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
+            Canvas c = new Canvas(thumbnail);
+            c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
+                    new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+            c.setBitmap(null);
+            // Recycle the old thumbnail
+            firstThumbnail.recycle();
+            return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
+                    thumbnail, taskRect.left, taskRect.top, this);
+        }
+
+        // If both the screenshot and thumbnail fails, then just fall back to the default transition
+        return getUnknownTransitionActivityOptions();
+    }
+
     /** Starts the recents activity */
     void startRecentsActivity(boolean isTopTaskHome) {
         // If Recents is not the front-most activity and we should animate into it.  If
@@ -498,39 +492,52 @@
         Rect taskRect = getAnimationTaskRect(recentTasks);
         boolean useThumbnailTransition = !isTopTaskHome &&
                 hasValidTaskRects();
+        boolean hasRecentTasks = !recentTasks.isEmpty();
 
         if (useThumbnailTransition) {
             // Try starting with a thumbnail transition
             ActivityOptions opts = getThumbnailTransitionActivityOptions(taskRect);
             if (opts != null) {
-                startAlternateRecentsActivity(opts, true);
+                if (sLastScreenshot != null) {
+                    startAlternateRecentsActivity(opts, EXTRA_FROM_APP_FULL_SCREENSHOT);
+                } else {
+                    startAlternateRecentsActivity(opts, EXTRA_FROM_APP_THUMBNAIL);
+                }
             } else {
                 // Fall through below to the non-thumbnail transition
                 useThumbnailTransition = false;
             }
+        } else {
+            // If there is no thumbnail transition, but is launching from home into recents, then
+            // use a quick home transition and do the animation from home
+            if (hasRecentTasks && Constants.DebugFlags.App.EnableHomeTransition) {
+                ActivityOptions opts = getHomeTransitionActivityOptions();
+                startAlternateRecentsActivity(opts, EXTRA_FROM_HOME);
+            } else {
+                // Otherwise we do the normal fade from an unknown source
+                ActivityOptions opts = getUnknownTransitionActivityOptions();
+                startAlternateRecentsActivity(opts, null);
+            }
         }
 
-        // If there is no thumbnail transition, then just use a generic transition
-        if (!useThumbnailTransition) {
-            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                    R.anim.recents_from_launcher_enter,
-                    R.anim.recents_from_launcher_exit, mHandler, this);
-            startAlternateRecentsActivity(opts, false);
+        if (Console.Enabled) {
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
         }
-
-        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
         mLastToggleTime = System.currentTimeMillis();
     }
 
     /** Starts the recents activity */
-    void startAlternateRecentsActivity(ActivityOptions opts, boolean animatingWithThumbnail) {
+    void startAlternateRecentsActivity(ActivityOptions opts, String extraFlag) {
         Intent intent = new Intent(sToggleRecentsAction);
         intent.setClassName(sRecentsPackage, sRecentsActivity);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail);
-        intent.putExtra(EXTRA_FROM_ALT_TAB, mTriggeredFromAltTab);
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+        if (extraFlag != null) {
+            intent.putExtra(extraFlag, true);
+        }
+        intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
         if (opts != null) {
             mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
                     UserHandle.USER_CURRENT));
@@ -539,6 +546,30 @@
         }
     }
 
+    /** Returns the last screenshot taken, this will be called by the RecentsActivity. */
+    public static Bitmap getLastScreenshot() {
+        return sLastScreenshot;
+    }
+
+    /** Recycles the last screenshot taken, this will be called by the RecentsActivity. */
+    public static void consumeLastScreenshot() {
+        if (sLastScreenshot != null) {
+            sLastScreenshot.recycle();
+            sLastScreenshot = null;
+        }
+    }
+
+    /** Sets the RecentsComponent callbacks. */
+    public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) {
+        sRecentsComponentCallbacks = cb;
+    }
+
+    /** Notifies the callbacks that the visibility of Recents has changed. */
+    public static void notifyVisibilityChanged(boolean visible) {
+        if (sRecentsComponentCallbacks != null) {
+            sRecentsComponentCallbacks.onVisibilityChanged(visible);
+        }
+    }
 
     /**** OnAnimationStartedListener Implementation ****/
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 76e88a5..1d355cd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -25,6 +25,10 @@
         public static final boolean Verbose = false;
 
         public static class App {
+            // Enables the home->Recents transition
+            public static final boolean EnableHomeTransition = true;
+            // Enables the screenshot app->Recents transition
+            public static final boolean EnableScreenshotAppTransition = false;
             // Enables the filtering of tasks according to their grouping
             public static final boolean EnableTaskFiltering = false;
             // Enables clipping of tasks against each other
@@ -52,8 +56,11 @@
         public static class App {
             public static final String TimeRecentsStartupKey = "startup";
             public static final String TimeRecentsLaunchKey = "launchTask";
-            public static final boolean TimeRecentsStartup = false;
-            public static final boolean TimeRecentsLaunchTask = false;
+            public static final String TimeRecentsScreenshotTransitionKey = "screenshot";
+            public static final boolean TimeRecentsStartup = true;
+            public static final boolean TimeRecentsLaunchTask = true;
+            public static final boolean TimeRecentsScreenshotTransition = true;
+
 
             public static final boolean RecentsComponent = false;
             public static final boolean TaskDataLoader = false;
@@ -106,7 +113,7 @@
             // The height of the peek space relative to the stack height
             public static final float StackPeekHeightPct = 0.1f;
             // The min scale of the last card in the peek area
-            public static final float StackPeekMinScale = 0.9f;
+            public static final float StackPeekMinScale = 0.8f;
             // The number of cards we see in the peek space
             public static final int StackPeekNumCards = 3;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java
new file mode 100644
index 0000000..247aa6f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java
@@ -0,0 +1,72 @@
+/*
+ * 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.os.Handler;
+
+/**
+ * A dozer is a class that fires a trigger after it falls asleep.  You can occasionally poke it to
+ * wake it up, but it will fall asleep if left untouched.
+ */
+public class DozeTrigger {
+
+    Handler mHandler;
+
+    boolean mIsDozing;
+    boolean mHasTriggered;
+    int mDozeDurationSeconds;
+    Runnable mSleepRunnable;
+
+    // Sleep-runnable
+    Runnable mDozeRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mSleepRunnable.run();
+            mIsDozing = false;
+            mHasTriggered = true;
+        }
+    };
+
+    public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) {
+        mHandler = new Handler();
+        mDozeDurationSeconds = dozeDurationSeconds;
+        mSleepRunnable = sleepRunnable;
+    }
+
+    /** Starts dozing. This also resets the trigger flag. */
+    public void startDozing() {
+        poke();
+        mHasTriggered = false;
+    }
+
+    /** Poke this dozer to wake it up for a little bit. */
+    public void poke() {
+        mHandler.removeCallbacks(mDozeRunnable);
+        mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000);
+        mIsDozing = true;
+    }
+
+    /** Returns whether we are dozing or not. */
+    public boolean isDozing() {
+        return mIsDozing;
+    }
+
+    /** Returns whether the trigger has fired at least once. */
+    public boolean hasTriggered() {
+        return mHasTriggered;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 8680786..dce8f57 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -22,11 +22,9 @@
 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.res.Configuration;
 import android.os.Bundle;
 import android.util.Pair;
 import android.view.Gravity;
@@ -34,15 +32,17 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.FullScreenTransitionView;
 import com.android.systemui.recents.views.RecentsView;
+import com.android.systemui.recents.views.ViewAnimation;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Set;
 
 /** Our special app widget host */
 class RecentsAppWidgetHost extends AppWidgetHost {
@@ -66,11 +66,16 @@
 
 /* Activity */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
-        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
+        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
+        FullScreenTransitionView.FullScreenTransitionViewCallbacks {
+
     FrameLayout mContainerView;
     RecentsView mRecentsView;
     View mEmptyView;
     View mNavBarScrimView;
+    FullScreenTransitionView mFullScreenshotView;
+
+    RecentsConfiguration mConfig;
 
     AppWidgetHost mAppWidgetHost;
     AppWidgetProviderInfo mSearchAppWidgetInfo;
@@ -79,6 +84,19 @@
     boolean mVisible;
     boolean mTaskLaunched;
 
+    private static Method sPropertyMethod;
+    static {
+        try {
+            Class<?> c = Class.forName("android.view.GLES20Canvas");
+            sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
+            if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        }
+    }
+
     // Broadcast receiver to handle messages from our RecentsService
     BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -93,8 +111,15 @@
                     // Dismiss recents, launching the focused task
                     dismissRecentsIfVisible();
                 } else {
-                    // Otherwise, just finish the activity without launching any other activities
-                    finish();
+                    // If we are mid-animation into Recents, then reverse it and finish
+                    if (mFullScreenshotView == null ||
+                            !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
+                        // Otherwise, just finish the activity without launching any other activities
+                        ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(context,
+                                null, mFinishRunnable, null);
+                        mRecentsView.startExitToHomeAnimation(
+                                new ViewAnimation.TaskViewExitContext(exitTrigger));
+                    }
                 }
             } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
                 // Try and unfilter and filtered stacks
@@ -104,7 +129,9 @@
                 }
             } else if (action.equals(RecentsService.ACTION_START_ENTER_ANIMATION)) {
                 // Try and start the enter animation (or restart it on configuration changed)
-                mRecentsView.startOnEnterAnimation();
+                mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenshotView));
+                // Call our callback
+                onEnterAnimationTriggered();
             }
         }
     };
@@ -113,19 +140,28 @@
     BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            // Mark recents as no longer visible
+            AlternateRecentsComponent.notifyVisibilityChanged(false);
+            // Finish without an animations
             finish();
         }
     };
 
+    // A runnable to finish the Recents activity
+    Runnable mFinishRunnable = new Runnable() {
+        @Override
+        public void run() {
+            // Mark recents as no longer visible
+            AlternateRecentsComponent.notifyVisibilityChanged(false);
+            // Finish with an animations
+            finish();
+            overridePendingTransition(R.anim.recents_to_launcher_enter,
+                    R.anim.recents_to_launcher_exit);
+        }
+    };
+
     /** Updates the set of recent tasks */
     void updateRecentsTasks(Intent launchIntent) {
-        // Update the configuration based on the launch intent
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false);
-        config.launchedFromAltTab = launchIntent.getBooleanExtra(
-                AlternateRecentsComponent.EXTRA_FROM_ALT_TAB, false);
-
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
         ArrayList<TaskStack> stacks = root.getStacks();
@@ -133,33 +169,37 @@
             mRecentsView.setBSP(root);
         }
 
-        // Hide the scrim by default when we enter recents
-        mNavBarScrimView.setVisibility(View.INVISIBLE);
+        // Update the configuration based on the launch intent
+        mConfig.launchedFromHome = launchIntent.getBooleanExtra(
+                AlternateRecentsComponent.EXTRA_FROM_HOME, false);
+        mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
+                AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
+        mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra(
+                AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false);
+        mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
+                AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
+        mConfig.launchedWithNoRecentTasks = !root.hasTasks();
+
+        if (mConfig.shouldAnimateNavBarScrim()) {
+            // Hide the scrim if we animate into Recents with window transitions
+            mNavBarScrimView.setVisibility(View.INVISIBLE);
+        } else {
+            // Show the scrim if we animate into Recents without window transitions
+            mNavBarScrimView.setVisibility(View.VISIBLE);
+        }
 
         // Add the default no-recents layout
-        if (stacks.size() == 1 && stacks.get(0).getTaskCount() == 0) {
+        if (mConfig.launchedWithNoRecentTasks) {
             mEmptyView.setVisibility(View.VISIBLE);
-
-            // Dim the background even more
-            WindowManager.LayoutParams wlp = getWindow().getAttributes();
-            wlp.dimAmount = Constants.Values.Window.DarkBackgroundDim;
-            getWindow().setAttributes(wlp);
-            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            mEmptyView.setBackgroundColor(0x80000000);
         } else {
             mEmptyView.setVisibility(View.GONE);
-
-            // Un-dim the background
-            WindowManager.LayoutParams wlp = getWindow().getAttributes();
-            wlp.dimAmount = 0f;
-            getWindow().setAttributes(wlp);
-            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         }
     }
 
     /** Attempts to allocate and bind the search bar app widget */
     void bindSearchBarAppWidget() {
         if (Constants.DebugFlags.App.EnableSearchLayout) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
             SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
 
             // Reset the host view and widget info
@@ -167,7 +207,7 @@
             mSearchAppWidgetInfo = null;
 
             // Try and load the app widget id from the settings
-            int appWidgetId = config.searchBarAppWidgetId;
+            int appWidgetId = mConfig.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
                 mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId);
                 if (mSearchAppWidgetInfo == null) {
@@ -197,7 +237,7 @@
                     }
 
                     // Save the app widget id into the settings
-                    config.updateSearchBarAppWidgetId(this, widgetInfo.first);
+                    mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first);
                     mSearchAppWidgetInfo = widgetInfo.second;
                 }
             }
@@ -207,8 +247,7 @@
     /** Creates the search bar app widget view */
     void addSearchBarAppWidgetView() {
         if (Constants.DebugFlags.App.EnableSearchLayout) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
-            int appWidgetId = config.searchBarAppWidgetId;
+            int appWidgetId = mConfig.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
                 if (Console.Enabled) {
                     Console.log(Constants.Log.App.SystemUIHandshake,
@@ -234,9 +273,19 @@
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
     boolean dismissRecentsIfVisible() {
         if (mVisible) {
-            if (!mRecentsView.launchFocusedTask()) {
-                if (!mRecentsView.launchFirstTask()) {
-                    finish();
+            // If we are mid-animation into Recents, then reverse it and finish
+            if (mFullScreenshotView == null ||
+                    !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
+                // If we have a focused task, then launch that task
+                if (!mRecentsView.launchFocusedTask()) {
+                    // If there are any tasks, then launch the first task
+                    if (!mRecentsView.launchFirstTask()) {
+                        // We really shouldn't hit this, but if we do, just animate out (aka. finish)
+                        ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+                                null, mFinishRunnable, null);
+                        mRecentsView.startExitToHomeAnimation(
+                                new ViewAnimation.TaskViewExitContext(exitTrigger));
+                    }
                 }
             }
             return true;
@@ -258,7 +307,7 @@
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
-        RecentsConfiguration.reinitialize(this);
+        mConfig = RecentsConfiguration.reinitialize(this);
 
         // Initialize the widget host (the host id is static and does not change)
         mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId, this);
@@ -277,16 +326,32 @@
         LayoutInflater inflater = LayoutInflater.from(this);
         mEmptyView = inflater.inflate(R.layout.recents_empty, mContainerView, false);
         mNavBarScrimView = inflater.inflate(R.layout.recents_nav_bar_scrim, mContainerView, false);
+        mNavBarScrimView.setLayoutParams(new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM));
+        if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+            mFullScreenshotView = new FullScreenTransitionView(this, this);
+            mFullScreenshotView.setLayoutParams(new FrameLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+        }
 
         mContainerView = new FrameLayout(this);
         mContainerView.addView(mRecentsView);
         mContainerView.addView(mEmptyView);
+        if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+            mContainerView.addView(mFullScreenshotView);
+        }
         mContainerView.addView(mNavBarScrimView);
         setContentView(mContainerView);
 
         // Update the recent tasks
         updateRecentsTasks(getIntent());
 
+        // Prepare the screenshot transition if necessary
+        if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+            mFullScreenshotView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot());
+        }
+
         // Bind the search app widget when we first start up
         bindSearchBarAppWidget();
         // Add the search bar layout
@@ -296,11 +361,23 @@
         if (savedInstanceState != null) {
             onConfigurationChange();
         }
+
+        // XXX: Update the shadows
+        try {
+            sPropertyMethod.invoke(null, "ambientShadowStrength", String.valueOf(35f));
+            sPropertyMethod.invoke(null, "ambientRatio", String.valueOf(0.5f));
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        }
     }
 
     void onConfigurationChange() {
         // Try and start the enter animation (or restart it on configuration changed)
-        mRecentsView.startOnEnterAnimation();
+        mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenshotView));
+        // Call our callback
+        onEnterAnimationTriggered();
     }
 
     @Override
@@ -319,11 +396,16 @@
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
-        RecentsConfiguration.reinitialize(this);
+        mConfig = RecentsConfiguration.reinitialize(this);
 
         // Update the recent tasks
         updateRecentsTasks(intent);
 
+        // Prepare the screenshot transition if necessary
+        if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+            mFullScreenshotView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot());
+        }
+
         // Don't attempt to rebind the search bar widget, but just add the search bar layout
         addSearchBarAppWidgetView();
     }
@@ -337,8 +419,7 @@
         super.onStart();
 
         // Start listening for widget package changes if there is one bound
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        if (config.searchBarAppWidgetId >= 0) {
+        if (mConfig.searchBarAppWidgetId >= 0) {
             mAppWidgetHost.startListening();
         }
 
@@ -412,8 +493,7 @@
         super.onStop();
 
         // Stop listening for widget package changes if there was one bound
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        if (config.searchBarAppWidgetId >= 0) {
+        if (mConfig.searchBarAppWidgetId >= 0) {
             mAppWidgetHost.stopListening();
         }
 
@@ -451,55 +531,99 @@
     }
 
     @Override
+    public void onUserInteraction() {
+        mRecentsView.onUserInteraction();
+    }
+
+    @Override
     public void onBackPressed() {
-        // Unfilter any stacks
-        if (!mRecentsView.unfilterFilteredStacks()) {
-            if (!mRecentsView.launchFirstTask()) {
-                super.onBackPressed();
+        // If we are mid-animation into Recents, then reverse it and finish
+        if (mFullScreenshotView == null ||
+                !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
+            // If we are currently filtering in any stacks, unfilter them first
+            if (!mRecentsView.unfilterFilteredStacks()) {
+                if (mConfig.launchedFromHome) {
+                    // Just start the animation out of recents
+                    ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+                            null, mFinishRunnable, null);
+                    mRecentsView.startExitToHomeAnimation(
+                            new ViewAnimation.TaskViewExitContext(exitTrigger));
+                } else {
+                    // Otherwise, try and launch the first task
+                    if (!mRecentsView.launchFirstTask()) {
+                        // If there are no tasks, then just finish recents
+                        ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+                                null, mFinishRunnable, null);
+                        mRecentsView.startExitToHomeAnimation(
+                                new ViewAnimation.TaskViewExitContext(exitTrigger));
+                    }
+                }
             }
         }
     }
 
-    @Override
     public void onEnterAnimationTriggered() {
         // Fade in the scrim
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        if (config.hasNavBarScrim()) {
+        if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) {
             mNavBarScrimView.setVisibility(View.VISIBLE);
-            mNavBarScrimView.setAlpha(0f);
-            mNavBarScrimView.animate().alpha(1f)
-                    .setStartDelay(config.taskBarEnterAnimDelay)
-                    .setDuration(config.navBarScrimEnterDuration)
-                    .setInterpolator(config.fastOutSlowInInterpolator)
-                    .withLayer()
+            mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
+            mNavBarScrimView.animate()
+                    .translationY(0)
+                    .setStartDelay(mConfig.taskBarEnterAnimDelay)
+                    .setDuration(mConfig.navBarScrimEnterDuration)
+                    .setInterpolator(mConfig.quintOutInterpolator)
                     .start();
         }
     }
 
     @Override
+    public void onExitAnimationTriggered() {
+        // Fade out the scrim
+        if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) {
+            mNavBarScrimView.animate()
+                    .translationY(mNavBarScrimView.getMeasuredHeight())
+                    .setStartDelay(0)
+                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                    .start();
+        }
+    }
+
+    @Override
+    public void onEnterAnimationComplete(boolean canceled) {
+        if (!canceled) {
+            // Reset the full screenshot transition view
+            if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+                mFullScreenshotView.reset();
+            }
+
+            // XXX: We should clean up the screenshot in this case as well, but it needs to happen
+            //      after to animate up
+        }
+        // Recycle the full screen screenshot
+        AlternateRecentsComponent.consumeLastScreenshot();
+    }
+
+    @Override
     public void onTaskLaunching(boolean isTaskInStackBounds) {
         mTaskLaunched = true;
 
         // Fade out the scrim
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        if (!isTaskInStackBounds && config.hasNavBarScrim()) {
-            mNavBarScrimView.animate().alpha(0f)
-                    .setStartDelay(0)
-                    .setDuration(config.taskBarExitAnimDuration)
-                    .setInterpolator(config.fastOutSlowInInterpolator)
-                    .withLayer()
-                    .start();
+        if (!isTaskInStackBounds && mConfig.hasNavBarScrim()) {
+            onExitAnimationTriggered();
         }
+
+        // Mark recents as no longer visible
+        AlternateRecentsComponent.notifyVisibilityChanged(false);
     }
 
     @Override
     public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-        if (appWidgetId > -1 && appWidgetId == config.searchBarAppWidgetId) {
+        if (appWidgetId > -1 && appWidgetId == mConfig.searchBarAppWidgetId) {
             // The search provider may have changed, so just delete the old widget and bind it again
             ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
-            config.updateSearchBarAppWidgetId(this, -1);
+            mConfig.updateSearchBarAppWidgetId(this, -1);
             // Load the widget again
             bindSearchBarAppWidget();
             addSearchBarAppWidgetView();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 0cf6ee6..c1a8ee6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -37,27 +37,40 @@
 
     DisplayMetrics mDisplayMetrics;
 
-    public Rect systemInsets = new Rect();
-    public Rect displayRect = new Rect();
-
-    boolean isLandscape;
-    boolean transposeRecentsLayoutWithOrientation;
-    int searchBarAppWidgetId = -1;
-
+    /** Animations */
     public float animationPxMovementPerSecond;
 
+    /** Interpolators */
     public Interpolator fastOutSlowInInterpolator;
     public Interpolator fastOutLinearInInterpolator;
     public Interpolator linearOutSlowInInterpolator;
+    public Interpolator quintOutInterpolator;
 
+    /** Filtering */
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
 
-    public int taskStackScrollDismissInfoPaneDistance;
-    public int taskStackMaxDim;
-    public float taskStackWidthPaddingPct;
-    public int taskStackTopPaddingPx;
+    /** Insets */
+    public Rect systemInsets = new Rect();
+    public Rect displayRect = new Rect();
 
+    /** Layout */
+    boolean isLandscape;
+    boolean transposeRecentsLayoutWithOrientation;
+
+    /** Search bar */
+    int searchBarAppWidgetId = -1;
+    public int searchBarSpaceHeightPx;
+
+    /** Task stack */
+    public int taskStackMaxDim;
+    public int taskStackTopPaddingPx;
+    public float taskStackWidthPaddingPct;
+
+    /** Task view animation and styles */
+    public int taskViewEnterFromHomeDuration;
+    public int taskViewEnterFromHomeDelay;
+    public int taskViewExitToHomeDuration;
     public int taskViewRemoveAnimDuration;
     public int taskViewRemoveAnimTranslationXPx;
     public int taskViewTranslationZMinPx;
@@ -66,23 +79,30 @@
     public int taskViewRoundedCornerRadiusPx;
     public int taskViewHighlightPx;
 
-    public int searchBarSpaceHeightPx;
-
+    /** Task bar colors */
     public int taskBarViewDefaultBackgroundColor;
     public int taskBarViewDefaultTextColor;
     public int taskBarViewLightTextColor;
     public int taskBarViewDarkTextColor;
     public int taskBarViewHighlightColor;
 
+    /** Task bar animations */
     public int taskBarEnterAnimDuration;
     public int taskBarEnterAnimDelay;
     public int taskBarExitAnimDuration;
+    public int taskBarDismissDozeDelaySeconds;
 
+    /** Nav bar scrim */
     public int navBarScrimEnterDuration;
 
-    public boolean launchedFromAltTab;
-    public boolean launchedWithThumbnailAnimation;
+    /** Launch states */
+    public boolean launchedWithAltTab;
+    public boolean launchedWithNoRecentTasks;
+    public boolean launchedFromAppWithThumbnail;
+    public boolean launchedFromAppWithScreenshot;
+    public boolean launchedFromHome;
 
+    /** Dev options */
     public boolean developerOptionsEnabled;
 
     /** Private constructor */
@@ -108,33 +128,56 @@
         DisplayMetrics dm = res.getDisplayMetrics();
         mDisplayMetrics = dm;
 
-        isLandscape = res.getConfiguration().orientation ==
-                Configuration.ORIENTATION_LANDSCAPE;
-        transposeRecentsLayoutWithOrientation =
-                res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout,
-                    "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
-                    Console.AnsiGreen);
-        }
-
-        displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
+        // Animations
         animationPxMovementPerSecond =
                 res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
+
+        // Interpolators
+        fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
+        linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
+        quintOutInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.decelerate_quint);
+
+        // Filtering
         filteringCurrentViewsMinAnimDuration =
                 res.getInteger(R.integer.recents_filter_animate_current_views_min_duration);
         filteringNewViewsMinAnimDuration =
                 res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
 
-        taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize(
-                R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance);
-        taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
+        // Insets
+        displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
 
+        // Layout
+        isLandscape = res.getConfiguration().orientation ==
+                Configuration.ORIENTATION_LANDSCAPE;
+        transposeRecentsLayoutWithOrientation =
+                res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
+
+        // Search bar
+        searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
+
+        // Update the search widget id
+        SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
+        searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
+
+        // Task stack
         TypedValue widthPaddingPctValue = new TypedValue();
         res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true);
         taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
+        taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
 
+        // Task view animation and styles
+        taskViewEnterFromHomeDuration =
+                res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
+        taskViewEnterFromHomeDelay =
+                res.getInteger(R.integer.recents_animate_task_enter_from_home_delay);
+        taskViewExitToHomeDuration =
+                res.getInteger(R.integer.recents_animate_task_exit_to_home_duration);
         taskViewRemoveAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_view_remove_duration);
         taskViewRemoveAnimTranslationXPx =
@@ -148,8 +191,7 @@
         taskViewShadowOutlineBottomInsetPx =
                 res.getDimensionPixelSize(R.dimen.recents_task_view_shadow_outline_bottom_inset);
 
-        searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
+        // Task bar colors
         taskBarViewDefaultBackgroundColor =
                 res.getColor(R.color.recents_task_bar_default_background_color);
         taskBarViewDefaultTextColor =
@@ -161,31 +203,30 @@
         taskBarViewHighlightColor =
                 res.getColor(R.color.recents_task_bar_highlight_color);
 
+        // Task bar animations
         taskBarEnterAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
         taskBarEnterAnimDelay =
                 res.getInteger(R.integer.recents_animate_task_bar_enter_delay);
         taskBarExitAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
+        taskBarDismissDozeDelaySeconds =
+                res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
 
+        // Nav bar scrim
         navBarScrimEnterDuration =
                 res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
 
-        fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                        com.android.internal.R.interpolator.fast_out_slow_in);
-        fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_linear_in);
-        linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.linear_out_slow_in);
-
         // Check if the developer options are enabled
         ContentResolver cr = context.getContentResolver();
         developerOptionsEnabled = Settings.Global.getInt(cr,
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
 
-        // Update the search widget id
-        SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
-        searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.MeasureAndLayout,
+                    "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
+                    Console.AnsiGreen);
+        }
     }
 
     /** Updates the system insets */
@@ -204,8 +245,11 @@
     /** Called when the configuration has changed, and we want to reset any configuration specific
      * members. */
     public void updateOnConfigurationChange() {
-        launchedFromAltTab = false;
-        launchedWithThumbnailAnimation = false;
+        launchedWithAltTab = false;
+        launchedWithNoRecentTasks = false;
+        launchedFromAppWithThumbnail = false;
+        launchedFromAppWithScreenshot = false;
+        launchedFromHome = false;
     }
 
     /** Returns whether the search bar app widget exists. */
@@ -213,9 +257,16 @@
         return searchBarAppWidgetId >= 0;
     }
 
+    /** Returns whether the nav bar scrim should be animated when shown for the first time. */
+    public boolean shouldAnimateNavBarScrim() {
+        return true;
+    }
+
     /** Returns whether the nav bar scrim should be visible. */
     public boolean hasNavBarScrim() {
-        return !transposeRecentsLayoutWithOrientation || !isLandscape;
+        // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
+        return !launchedWithNoRecentTasks &&
+                (!transposeRecentsLayoutWithOrientation || !isLandscape);
     }
 
     /**
@@ -257,15 +308,4 @@
             searchBarSpaceBounds.set(0, 0, width, searchBarSpaceHeightPx);
         }
     }
-
-    /** Converts from DPs to PXs */
-    public int pxFromDp(float size) {
-        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                size, mDisplayMetrics));
-    }
-    /** Converts from SPs to PXs */
-    public int pxFromSp(float size) {
-        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
-                size, mDisplayMetrics));
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 0c2c11d..e554af7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -121,6 +121,7 @@
             // Send a broadcast to hide recents
             Intent intent = new Intent(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
             intent.setPackage(context.getPackageName());
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             if (msg.arg1 != 0) {
                 intent.putExtra(RecentsService.EXTRA_TRIGGERED_FROM_ALT_TAB, true);
             }
@@ -129,17 +130,21 @@
             // Send a broadcast to toggle recents
             Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
             intent.setPackage(context.getPackageName());
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             context.sendBroadcast(intent);
 
             // Time this path
-            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
-            Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                    Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+            if (Console.Enabled) {
+                Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                        Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
+                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                        Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+            }
         } else if (msg.what == AlternateRecentsComponent.MSG_START_ENTER_ANIMATION) {
             // Send a broadcast to start the enter animation
             Intent intent = new Intent(RecentsService.ACTION_START_ENTER_ANIMATION);
             intent.setPackage(context.getPackageName());
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             context.sendBroadcast(intent);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 4685186..a02e1a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -394,7 +394,7 @@
 
         SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RecentTaskInfo> tasks =
-                ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
+                ssp.getRecentTasks(100, UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
         if (Console.Enabled) {
             Console.log(Constants.Log.App.TimeSystemCalls,
@@ -478,7 +478,7 @@
                 // Load the thumbnail (if possible and not the foremost task, from the cache)
                 if (!isForemostTask) {
                     task.thumbnail = mThumbnailCache.get(task.key);
-                    if (task.thumbnail != null) {
+                    if (task.thumbnail != null && !tasksToForceLoad.contains(task)) {
                         // Even though we get things from the cache, we should update them if
                         // they've changed in the bg
                         tasksToForceLoad.add(task);
@@ -489,6 +489,7 @@
                         Console.log(Constants.Log.App.TaskDataLoader,
                                 "[RecentsTaskLoader|loadingTaskThumbnail]");
                     }
+
                     task.thumbnail = ssp.getTaskThumbnail(task.key.id);
                     if (task.thumbnail != null) {
                         task.thumbnail.setHasAlpha(false);
@@ -512,20 +513,6 @@
                     "" + (System.currentTimeMillis() - t1) + "ms");
         }
 
-        /*
-        // Get all the stacks
-        t1 = System.currentTimeMillis();
-        List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
-        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.Log.App.TaskDataLoader, "  [RecentsTaskLoader|stack]", s.toString());
-            if (stacks.containsKey(s.stackId)) {
-                stacks.get(s.stackId).setRect(s.bounds);
-            }
-        }
-        */
-
         // Start the task loader
         mLoader.start(context);
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java
new file mode 100644
index 0000000..2f89e6d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.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.recents;
+
+import android.content.Context;
+
+/**
+ * A ref counted trigger that does some logic when the count is first incremented, or last
+ * decremented.  Not thread safe as it's not currently needed.
+ */
+public class ReferenceCountedTrigger {
+
+    Context mContext;
+    int mCount;
+    Runnable mFirstIncRunnable;
+    Runnable mLastDecRunnable;
+    Runnable mErrorRunnable;
+
+    // Convenience runnables
+    Runnable mIncrementRunnable = new Runnable() {
+        @Override
+        public void run() {
+            increment();
+        }
+    };
+    Runnable mDecrementRunnable = new Runnable() {
+        @Override
+        public void run() {
+            decrement();
+        }
+    };
+
+    public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable,
+                                   Runnable lastDecRunnable, Runnable errorRunanable) {
+        mContext = context;
+        mFirstIncRunnable = firstIncRunnable;
+        mLastDecRunnable = lastDecRunnable;
+        mErrorRunnable = errorRunanable;
+    }
+
+    /** Increments the ref count */
+    public void increment() {
+        if (mCount == 0 && mFirstIncRunnable != null) {
+            mFirstIncRunnable.run();
+        }
+        mCount++;
+    }
+
+    /** Convenience method to increment this trigger as a runnable */
+    public Runnable incrementAsRunnable() {
+        return mIncrementRunnable;
+    }
+
+    /** Decrements the ref count */
+    public void decrement() {
+        mCount--;
+        if (mCount == 0 && mLastDecRunnable != null) {
+            mLastDecRunnable.run();
+        } else if (mCount < 0) {
+            if (mErrorRunnable != null) {
+                mErrorRunnable.run();
+            } else {
+                new Throwable("Invalid ref count").printStackTrace();
+                Console.logError(mContext, "Invalid ref count");
+            }
+        }
+    }
+
+    /** Convenience method to decrement this trigger as a runnable */
+    public Runnable decrementAsRunnable() {
+        return mDecrementRunnable;
+    }
+
+    /** Returns the current ref count */
+    public int getCount() {
+        return mCount;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 7a3ffb8..c47f7d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -30,13 +30,23 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Log;
 import android.util.Pair;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -48,16 +58,22 @@
  * a point of injection when testing UI.
  */
 public class SystemServicesProxy {
+    final static String TAG = "SystemServicesProxy";
+
     ActivityManager mAm;
     AppWidgetManager mAwm;
     PackageManager mPm;
     IPackageManager mIpm;
     UserManager mUm;
     SearchManager mSm;
+    WindowManager mWm;
+    Display mDisplay;
     String mRecentsPackage;
     ComponentName mAssistComponent;
 
     Bitmap mDummyIcon;
+    Paint mBgProtectionPaint;
+    Canvas mBgProtectionCanvas;
 
     /** Private constructor */
     public SystemServicesProxy(Context context) {
@@ -67,8 +83,16 @@
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mIpm = AppGlobals.getPackageManager();
         mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
+        mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
 
+        // Create the protection paints
+        mBgProtectionPaint = new Paint();
+        mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
+        mBgProtectionPaint.setColor(0xFFffffff);
+        mBgProtectionCanvas = new Canvas();
+
         // Resolve the assist intent
         Intent assist = mSm.getAssistIntent(context, false);
         if (assist != null) {
@@ -184,7 +208,20 @@
             return thumbnail;
         }
 
-        return mAm.getTaskTopThumbnail(taskId);
+        Bitmap thumbnail = mAm.getTaskTopThumbnail(taskId);
+        if (thumbnail != null) {
+            // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
+            // left pixel, then assume the whole thumbnail is transparent. Generally, proper
+            // screenshots are always composed onto a bitmap that has no alpha.
+            if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) {
+                mBgProtectionCanvas.setBitmap(thumbnail);
+                mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(),
+                        mBgProtectionPaint);
+                mBgProtectionCanvas.setBitmap(null);
+                Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
+            }
+        }
+        return thumbnail;
     }
 
     /** Moves a task to the front with the specified activity options */
@@ -325,4 +362,13 @@
         // Delete the app widget
         host.deleteAppWidgetId(appWidgetId);
     }
+
+    /**
+     * Takes a screenshot of the current surface.
+     */
+    public Bitmap takeScreenshot() {
+        DisplayInfo di = new DisplayInfo();
+        mDisplay.getDisplayInfo(di);
+        return SurfaceControl.screenshot(di.getNaturalWidth(), di.getNaturalHeight());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
index 1dd1be6..20be415 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
@@ -56,6 +56,13 @@
         return mStack;
     }
 
+    /** Returns whether there are any tasks in any stacks below this node. */
+    public boolean hasTasks() {
+        return (mStack.getTaskCount() > 0) ||
+                (mStartNode != null && mStartNode.hasTasks()) ||
+                (mEndNode != null && mEndNode.hasTasks());
+    }
+
     /** Returns whether this is a leaf node */
     boolean isLeafNode() {
         return (mStartNode == null) && (mEndNode == null);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 47a506c..f366ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.model;
 
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
new file mode 100644
index 0000000..c861d2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
@@ -0,0 +1,238 @@
+/*
+ * 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.views;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import com.android.systemui.recents.Console;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
+
+
+/**
+ * The full screen transition view that gets animated down from the full screen into a task
+ * thumbnail view.
+ */
+public class FullScreenTransitionView extends FrameLayout {
+
+    /** The FullScreenTransitionView callbacks */
+    public interface FullScreenTransitionViewCallbacks {
+        void onEnterAnimationComplete(boolean canceled);
+    }
+
+    RecentsConfiguration mConfig;
+
+    FullScreenTransitionViewCallbacks mCb;
+
+    ImageView mScreenshotView;
+
+    Rect mClipRect = new Rect();
+
+    boolean mIsAnimating;
+    AnimatorSet mEnterAnimation;
+
+    public FullScreenTransitionView(Context context, FullScreenTransitionViewCallbacks cb) {
+        super(context);
+        mConfig = RecentsConfiguration.getInstance();
+        mCb = cb;
+        mScreenshotView = new ImageView(context);
+        mScreenshotView.setScaleType(ImageView.ScaleType.FIT_XY);
+        mScreenshotView.setLayoutParams(new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+        addView(mScreenshotView);
+        setClipTop(getClipTop());
+        setClipBottom(getClipBottom());
+        setWillNotDraw(false);
+    }
+
+    /** Sets the top clip */
+    public void setClipTop(int clip) {
+        mClipRect.top = clip;
+        postInvalidateOnAnimation();
+    }
+
+    /** Gets the top clip */
+    public int getClipTop() {
+        return mClipRect.top;
+    }
+
+    /** Sets the bottom clip */
+    public void setClipBottom(int clip) {
+        mClipRect.bottom = clip;
+        postInvalidateOnAnimation();
+    }
+
+    /** Gets the top clip */
+    public int getClipBottom() {
+        return mClipRect.bottom;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mClipRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+        canvas.clipRect(mClipRect);
+        super.draw(canvas);
+        canvas.restoreToCount(restoreCount);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    /** Prepares the screenshot view for the transition into Recents */
+    public void prepareAnimateOnEnterRecents(Bitmap screenshot) {
+        if (!mConfig.launchedFromAppWithScreenshot) return;
+
+        if (Console.Enabled) {
+            Console.logStartTracingTime(Constants.Log.App.TimeRecentsScreenshotTransition,
+                    Constants.Log.App.TimeRecentsScreenshotTransitionKey);
+        }
+
+        setClipTop(0);
+        setClipBottom(getMeasuredHeight());
+        setTranslationY(0f);
+        setScaleX(1f);
+        setScaleY(1f);
+        setVisibility(mConfig.launchedFromAppWithScreenshot ? View.VISIBLE : View.INVISIBLE);
+        if (screenshot != null) {
+            mScreenshotView.setImageBitmap(screenshot);
+        } else {
+            mScreenshotView.setImageDrawable(null);
+        }
+    }
+
+    /** Resets the transition view */
+    public void reset() {
+        setVisibility(View.INVISIBLE);
+        mScreenshotView.setImageDrawable(null);
+    }
+
+    /** Animates this view as it enters recents */
+    public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx,
+                                      final Runnable postAnimRunnable) {
+        if (Console.Enabled) {
+            Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
+                    Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Starting");
+        }
+
+        // Cancel the current animation
+        if (mEnterAnimation != null) {
+            mEnterAnimation.removeAllListeners();
+            mEnterAnimation.cancel();
+        }
+
+        // Calculate the bottom clip
+        float scale = (float) ctx.taskRect.width() / getMeasuredWidth();
+        int translationY = -mConfig.systemInsets.top + ctx.stackRectSansPeek.top +
+                ctx.transform.translationY;
+        int clipBottom = mConfig.systemInsets.top + (int) (ctx.taskRect.height() / scale);
+
+        // Enable the HW Layers on the screenshot view
+        mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+
+        // Compose the animation
+        mEnterAnimation = new AnimatorSet();
+        mEnterAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Notify any callbacks
+                mCb.onEnterAnimationComplete(false);
+                // Run the given post-anim runnable
+                postAnimRunnable.run();
+                // Mark that we are no longer animating
+                mIsAnimating = false;
+                // Disable the HW Layers on this view
+                setLayerType(View.LAYER_TYPE_NONE, null);
+
+                if (Console.Enabled) {
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
+                            Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Completed");
+                }
+            }
+        });
+        mEnterAnimation.setStartDelay(0);
+        mEnterAnimation.setDuration(475);
+        mEnterAnimation.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        mEnterAnimation.playTogether(
+                ObjectAnimator.ofInt(this, "clipTop", mConfig.systemInsets.top),
+                ObjectAnimator.ofInt(this, "clipBottom", clipBottom),
+                ObjectAnimator.ofFloat(this, "translationY", translationY),
+                ObjectAnimator.ofFloat(this, "scaleX", scale),
+                ObjectAnimator.ofFloat(this, "scaleY", scale)
+        );
+        mEnterAnimation.start();
+
+        mIsAnimating = true;
+    }
+
+    /** Animates this view back out of Recents if we were in the process of animating in. */
+    public boolean cancelAnimateOnEnterRecents(final Runnable postAnimRunnable) {
+        if (mIsAnimating) {
+            // Cancel the current animation
+            if (mEnterAnimation != null) {
+                mEnterAnimation.removeAllListeners();
+                mEnterAnimation.cancel();
+            }
+
+            // Compose the animation
+            mEnterAnimation = new AnimatorSet();
+            mEnterAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    // Notify any callbacks
+                    mCb.onEnterAnimationComplete(true);
+                    // Run the given post-anim runnable
+                    postAnimRunnable.run();
+                    // Mark that we are no longer animating
+                    mIsAnimating = false;
+                    // Disable the HW Layers on the screenshot view
+                    mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
+            });
+            mEnterAnimation.setDuration(475);
+            mEnterAnimation.setInterpolator(mConfig.fastOutSlowInInterpolator);
+            mEnterAnimation.playTogether(
+                    ObjectAnimator.ofInt(this, "clipTop", 0),
+                    ObjectAnimator.ofInt(this, "clipBottom", getMeasuredHeight()),
+                    ObjectAnimator.ofFloat(this, "translationY", 0f),
+                    ObjectAnimator.ofFloat(this, "scaleX", 1f),
+                    ObjectAnimator.ofFloat(this, "scaleY", 1f)
+            );
+            mEnterAnimation.start();
+
+            return true;
+        }
+        return false;
+    }
+}
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 db398b1..3e6879d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -55,9 +55,12 @@
     /** The RecentsView callbacks */
     public interface RecentsViewCallbacks {
         public void onTaskLaunching(boolean isTaskInStackBounds);
-        public void onEnterAnimationTriggered();
+        public void onExitAnimationTriggered();
     }
 
+    RecentsConfiguration mConfig;
+    LayoutInflater mInflater;
+
     // The space partitioning root of this container
     SpaceNode mBSP;
     // Whether there are any tasks
@@ -67,12 +70,10 @@
     // Recents view callbacks
     RecentsViewCallbacks mCb;
 
-    LayoutInflater mInflater;
-
     public RecentsView(Context context) {
         super(context);
+        mConfig = RecentsConfiguration.getInstance();
         mInflater = LayoutInflater.from(context);
-        setWillNotDraw(false);
     }
 
     /** Sets the callbacks */
@@ -160,20 +161,42 @@
     }
 
     /** Requests all task stacks to start their enter-recents animation */
-    public void startOnEnterAnimation() {
-        // Notify callbacks that we are starting the enter animation
-        mCb.onEnterAnimationTriggered();
-
+    public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
             if (child instanceof TaskStackView) {
                 TaskStackView stackView = (TaskStackView) child;
-                stackView.startOnEnterAnimation();
+                stackView.startEnterRecentsAnimation(ctx);
             }
         }
     }
 
+    /** Requests all task stacks to start their exit-recents animation */
+    public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+        // Handle the case when there are no views by incrementing and decrementing after all
+        // animations are started.
+        ctx.postAnimationTrigger.increment();
+
+        if (Constants.DebugFlags.App.EnableHomeTransition) {
+            int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                if (child instanceof TaskStackView) {
+                    TaskStackView stackView = (TaskStackView) child;
+                    stackView.startExitToHomeAnimation(ctx);
+                }
+            }
+        }
+
+        // Handle the case when there are no views by incrementing and decrementing after all
+        // animations are started.
+        ctx.postAnimationTrigger.decrement();
+
+        // Notify of the exit animation
+        mCb.onExitAnimationTriggered();
+    }
+
     /** Adds the search bar */
     public void setSearchBar(View searchBar) {
         // Create the search bar (and hide it if we have no recent tasks)
@@ -215,10 +238,9 @@
         }
 
         // Get the search bar bounds and measure the search bar layout
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
         if (mSearchBar != null) {
             Rect searchBarSpaceBounds = new Rect();
-            config.getSearchBarBounds(width, height - config.systemInsets.top, searchBarSpaceBounds);
+            mConfig.getSearchBarBounds(width, height - mConfig.systemInsets.top, searchBarSpaceBounds);
             mSearchBar.measure(
                     MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
                     MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
@@ -229,9 +251,9 @@
         // In addition, we give it the full height, not including the top inset or search bar space,
         // since we want the tasks to render under the navigation buttons in portrait.
         Rect taskStackBounds = new Rect();
-        config.getTaskStackBounds(width, height, taskStackBounds);
-        int childWidth = width - config.systemInsets.right;
-        int childHeight = taskStackBounds.height() - config.systemInsets.top;
+        mConfig.getTaskStackBounds(width, height, taskStackBounds);
+        int childWidth = width - mConfig.systemInsets.right;
+        int childHeight = taskStackBounds.height() - mConfig.systemInsets.top;
 
         // Measure each TaskStackView
         int childCount = getChildCount();
@@ -259,23 +281,22 @@
         }
 
         // Get the search bar bounds so that we lay it out
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
         if (mSearchBar != null) {
             Rect searchBarSpaceBounds = new Rect();
-            config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds);
-            mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
-                    config.systemInsets.top + searchBarSpaceBounds.top,
-                    config.systemInsets.left + mSearchBar.getMeasuredWidth(),
-                    config.systemInsets.top + mSearchBar.getMeasuredHeight());
+            mConfig.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds);
+            mSearchBar.layout(mConfig.systemInsets.left + searchBarSpaceBounds.left,
+                    mConfig.systemInsets.top + searchBarSpaceBounds.top,
+                    mConfig.systemInsets.left + mSearchBar.getMeasuredWidth(),
+                    mConfig.systemInsets.top + mSearchBar.getMeasuredHeight());
         }
 
         // We offset the stack view by the left inset (if any), but lay it out under the search bar.
         // In addition, we offset our stack views by the top inset and search bar height, but not
         // the bottom insets because we want it to render under the navigation buttons.
         Rect taskStackBounds = new Rect();
-        config.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds);
-        left += config.systemInsets.left;
-        top += config.systemInsets.top + taskStackBounds.top;
+        mConfig.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds);
+        left += mConfig.systemInsets.left;
+        top += mConfig.systemInsets.top + taskStackBounds.top;
 
         // Layout each child
         // XXX: Based on the space node for that task view
@@ -289,6 +310,20 @@
         }
     }
 
+    /** Notifies each task view of the user interaction. */
+    public void onUserInteraction() {
+        // Get the first stack view
+        TaskStackView stackView = null;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView) {
+                stackView = (TaskStackView) child;
+                stackView.onUserInteraction();
+            }
+        }
+    }
+
     /** Focuses the next task in the first stack view */
     public void focusNextTask(boolean forward) {
         // Get the first stack view
@@ -324,8 +359,7 @@
         }
 
         // Update the configuration with the latest system insets and trigger a relayout
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        config.updateSystemInsets(insets.getSystemWindowInsets());
+        mConfig.updateSystemInsets(insets.getSystemWindowInsets());
         requestLayout();
 
         return insets.consumeSystemWindowInsets(false, false, false, true);
@@ -365,6 +399,11 @@
         final Runnable launchRunnable = new Runnable() {
             @Override
             public void run() {
+                if (Console.Enabled) {
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                            Constants.Log.App.TimeRecentsLaunchKey, "preStartActivity");
+                }
+
                 TaskViewTransform transform;
                 View sourceView = tv;
                 int offsetX = 0;
@@ -374,11 +413,10 @@
                     // If there is no actual task view, then use the stack view as the source view
                     // and then offset to the expected transform rect, but bound this to just
                     // outside the display rect (to ensure we don't animate from too far away)
-                    RecentsConfiguration config = RecentsConfiguration.getInstance();
                     sourceView = stackView;
                     transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
                     offsetX = transform.rect.left;
-                    offsetY = Math.min(transform.rect.top, config.displayRect.height());
+                    offsetY = Math.min(transform.rect.top, mConfig.displayRect.height());
                 } else {
                     transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
                 }
@@ -426,19 +464,23 @@
                     onTaskRemoved(task);
                 }
 
-                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                        Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
+                if (Console.Enabled) {
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                            Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
+                }
             }
         };
 
-        Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
+        if (Console.Enabled) {
+            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) {
             post(launchRunnable);
         } else {
-            tv.animateOnLeavingRecents(launchRunnable);
+            stackView.animateOnLaunchingTask(tv, launchRunnable);
         }
     }
 
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 c10ddd1..82d6220 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -24,6 +24,8 @@
 import android.graphics.PorterDuffXfermode;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -36,6 +38,9 @@
 
 /* The task bar view */
 class TaskBarView extends FrameLayout {
+
+    RecentsConfiguration mConfig;
+
     Task mTask;
 
     ImageView mDismissButton;
@@ -61,6 +66,7 @@
 
     public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mConfig = RecentsConfiguration.getInstance();
         setWillNotDraw(false);
 
         // Load the dismiss resources
@@ -70,11 +76,10 @@
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
             sHighlightPaint = new Paint();
             sHighlightPaint.setStyle(Paint.Style.STROKE);
-            sHighlightPaint.setStrokeWidth(config.taskViewHighlightPx);
-            sHighlightPaint.setColor(config.taskBarViewHighlightColor);
+            sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx);
+            sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor);
             sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
             sHighlightPaint.setAntiAlias(true);
         }
@@ -90,39 +95,42 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-
         // Draw the highlight at the top edge (but put the bottom edge just out of view)
-        float offset = config.taskViewHighlightPx / 2f;
-        float radius = config.taskViewRoundedCornerRadiusPx;
+        float offset = mConfig.taskViewHighlightPx / 2f;
+        float radius = mConfig.taskViewRoundedCornerRadiusPx;
         canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
                 getMeasuredHeight() + radius, radius, radius, sHighlightPaint);
     }
 
     /** 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)
+    void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) {
+        if (duration > 0 && (mDismissButton.getVisibility() == View.VISIBLE)) {
+            ViewPropertyAnimator anim = mDismissButton.animate();
+
+            // Animate to the final state
+            if (toTransform.hasDismissAlphaChangedFrom(mDismissButton.getAlpha())) {
+                anim.alpha(toTransform.dismissAlpha)
                     .setStartDelay(0)
                     .setDuration(duration)
-                    .setInterpolator(config.fastOutSlowInInterpolator)
+                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
                     .withLayer()
                     .start();
+            }
         } else {
-            mDismissButton.setAlpha(toTransform.dismissAlpha);
+            // Set the changed properties
+            if (toTransform.hasDismissAlphaChangedFrom(mDismissButton.getAlpha())) {
+                mDismissButton.setAlpha(toTransform.dismissAlpha);
+            }
         }
-        mDismissButton.invalidate();
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
     }
 
     /** Binds the bar view to the task */
     void rebindToTask(Task t, boolean animate) {
-        RecentsConfiguration configuration = RecentsConfiguration.getInstance();
         mTask = t;
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
         // otherwise, we fall back to the application icon
@@ -137,15 +145,12 @@
         if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
             setBackgroundColor(tint);
             mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint,
-                    configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor));
+                    mConfig.taskBarViewLightTextColor, mConfig.taskBarViewDarkTextColor));
             mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint,
                     mLightDismissDrawable, mDarkDismissDrawable));
         } else {
-            setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
-            mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
-        }
-        if (animate) {
-            // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
+            setBackgroundColor(mConfig.taskBarViewDefaultBackgroundColor);
+            mActivityDescription.setTextColor(mConfig.taskBarViewDefaultTextColor);
         }
     }
 
@@ -155,4 +160,88 @@
         mApplicationIcon.setImageDrawable(null);
         mActivityDescription.setText("");
     }
+
+    /** Prepares this task view for the enter-recents animations.  This is called earlier in the
+     * first layout because the actual animation into recents may take a long time. */
+    public void prepareEnterRecentsAnimation() {
+        setVisibility(View.INVISIBLE);
+    }
+
+    /** Animates this task bar as it enters recents */
+    public void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
+        // Animate the task bar of the first task view
+        setVisibility(View.VISIBLE);
+        setTranslationY(-getMeasuredHeight());
+        animate()
+                .translationY(0)
+                .setStartDelay(delay)
+                .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                .setDuration(mConfig.taskBarEnterAnimDuration)
+                .withEndAction(postAnimRunnable)
+                .start();
+    }
+
+    /** Animates this task bar as it exits recents */
+    public void startLaunchTaskAnimation(Runnable preAnimRunnable, final Runnable postAnimRunnable) {
+        // Animate the task bar out of the first task view
+        animate()
+                .translationY(-getMeasuredHeight())
+                .setStartDelay(0)
+                .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                .setDuration(mConfig.taskBarExitAnimDuration)
+                .withStartAction(preAnimRunnable)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        post(postAnimRunnable);
+                    }
+                })
+                .start();
+    }
+
+    /** Animates this task bar dismiss button when launching a task. */
+    public void startLaunchTaskDismissAnimation() {
+        if (mDismissButton.getVisibility() == View.VISIBLE) {
+            mDismissButton.animate().cancel();
+            mDismissButton.animate()
+                    .alpha(0f)
+                    .setStartDelay(0)
+                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                    .setDuration(mConfig.taskBarExitAnimDuration)
+                    .withLayer()
+                    .start();
+        }
+    }
+
+    /** Animates this task bar if the user does not interact with the stack after a certain time. */
+    public void startNoUserInteractionAnimation() {
+        mDismissButton.setVisibility(View.VISIBLE);
+        mDismissButton.setAlpha(0f);
+        mDismissButton.animate()
+                .alpha(1f)
+                .setStartDelay(0)
+                .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                .setDuration(mConfig.taskBarEnterAnimDuration)
+                .withLayer()
+                .start();
+    }
+
+    /** Mark this task view that the user does has not interacted with the stack after a certain time. */
+    public void setNoUserInteractionState() {
+        if (mDismissButton.getVisibility() != View.VISIBLE) {
+            mDismissButton.animate().cancel();
+            mDismissButton.setVisibility(View.VISIBLE);
+            mDismissButton.setAlpha(1f);
+        }
+    }
+
+    /** Enable the hw layers on this task view */
+    void enableHwLayers() {
+        mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+    }
+
+    /** Disable the hw layers on this task view */
+    void disableHwLayers() {
+        mDismissButton.setLayerType(View.LAYER_TYPE_NONE, null);
+    }
 }
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 5830e37..e0a12b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -38,9 +38,11 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.DozeTrigger;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsPackageMonitor;
 import com.android.systemui.recents.RecentsTaskLoader;
+import com.android.systemui.recents.ReferenceCountedTrigger;
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
@@ -62,10 +64,14 @@
         public void onTaskRemoved(Task t);
     }
 
+    RecentsConfiguration mConfig;
+
     TaskStack mStack;
     TaskStackViewTouchHandler mTouchHandler;
     TaskStackViewCallbacks mCb;
     ViewPool<TaskView, Task> mViewPool;
+    ArrayList<TaskViewTransform> mTaskTransforms = new ArrayList<TaskViewTransform>();
+    DozeTrigger mDozeTrigger;
 
     // The various rects that define the stack view
     Rect mRect = new Rect();
@@ -83,11 +89,12 @@
     ObjectAnimator mScrollAnimator;
 
     // Optimizations
-    int mHwLayersRefCount;
+    ReferenceCountedTrigger mHwLayersTrigger;
     int mStackViewsAnimationDuration;
     boolean mStackViewsDirty = true;
     boolean mAwaitingFirstLayout = true;
     boolean mStartEnterAnimationRequestedAfterLayout;
+    ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
     int[] mTmpVisibleRange = new int[2];
     Rect mTmpRect = new Rect();
     Rect mTmpRect2 = new Rect();
@@ -95,12 +102,51 @@
 
     public TaskStackView(Context context, TaskStack stack) {
         super(context);
+        mConfig = RecentsConfiguration.getInstance();
         mStack = stack;
         mStack.setCallbacks(this);
         mScroller = new OverScroller(context);
         mTouchHandler = new TaskStackViewTouchHandler(context, this);
         mViewPool = new ViewPool<TaskView, Task>(context, this);
         mInflater = LayoutInflater.from(context);
+        mDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
+            @Override
+            public void run() {
+                // Show the task bar dismiss buttons
+                int childCount = getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                    TaskView tv = (TaskView) getChildAt(i);
+                    tv.startNoUserInteractionAnimation();
+                }
+            }
+        });
+        mHwLayersTrigger = new ReferenceCountedTrigger(getContext(), new Runnable() {
+            @Override
+            public void run() {
+                // Enable hw layers on each of the children
+                int childCount = getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                    TaskView tv = (TaskView) getChildAt(i);
+                    tv.enableHwLayers();
+                }
+            }
+        }, new Runnable() {
+            @Override
+            public void run() {
+                // Disable hw layers on each of the children
+                int childCount = getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                    TaskView tv = (TaskView) getChildAt(i);
+                    tv.disableHwLayers();
+                }
+            }
+        }, new Runnable() {
+            @Override
+            public void run() {
+                new Throwable("Invalid hw layers ref count").printStackTrace();
+                Console.logError(getContext(), "Invalid HW layers ref count");
+            }
+        });
     }
 
     /** Sets the callbacks */
@@ -118,7 +164,7 @@
                     "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
         }
         if (!mStackViewsDirty) {
-            invalidate();
+            invalidate(mStackRect);
         }
         if (mAwaitingFirstLayout) {
             // Skip the animation if we are awaiting first layout
@@ -129,7 +175,7 @@
         mStackViewsDirty = true;
     }
 
-    // XXX: Optimization: Use a mapping of Task -> View
+    /** Finds the child view given a specific task */
     private TaskView getChildViewForTask(Task t) {
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -156,14 +202,16 @@
         float boundedT = Math.max(t, -(numPeekCards + 1));
 
         // Set the scale relative to its position
+        int numFrontScaledCards = 3;
         float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
         float scaleRange = 1f - minScale;
-        float scaleInc = scaleRange / numPeekCards;
-        float scale = Math.max(minScale, Math.min(1f, 1f + (boundedT * scaleInc)));
+        float scaleInc = scaleRange / (numPeekCards + numFrontScaledCards);
+        float scale = Math.max(minScale, Math.min(1f, minScale + 
+            ((boundedT + (numPeekCards + 1)) * scaleInc)));
         float scaleYOffset = ((1f - scale) * mTaskRect.height()) / 2;
         transform.scale = scale;
 
-        // Set the translation
+        // Set the y translation
         if (boundedT < 0f) {
             transform.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
                     numPeekCards) * peekHeight - scaleYOffset);
@@ -171,6 +219,11 @@
             transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
         }
 
+        // Set the z translation
+        int minZ = mConfig.taskViewTranslationZMinPx;
+        int incZ = mConfig.taskViewTranslationZIncrementPx;
+        transform.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
+
         // Set the alphas
         transform.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
 
@@ -190,16 +243,18 @@
     /**
      * Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
      */
-    private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
-                                                            int stackScroll,
-                                                            int[] visibleRangeOut,
-                                                            boolean boundTranslationsToRect) {
+    private void updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms,
+                                       ArrayList<Task> tasks,
+                                       int stackScroll,
+                                       int[] visibleRangeOut,
+                                       boolean boundTranslationsToRect) {
         // XXX: Optimization: Use binary search to find the visible range
 
-        ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
         int taskCount = tasks.size();
         int firstVisibleIndex = -1;
         int lastVisibleIndex = -1;
+        taskTransforms.clear();
+        taskTransforms.ensureCapacity(taskCount);
         for (int i = 0; i < taskCount; i++) {
             TaskViewTransform transform = getStackTransform(i, stackScroll);
             taskTransforms.add(transform);
@@ -218,6 +273,19 @@
             visibleRangeOut[0] = firstVisibleIndex;
             visibleRangeOut[1] = lastVisibleIndex;
         }
+    }
+
+    /**
+     * Gets the stack transforms of a list of tasks, and returns the visible range of tasks. This
+     * call is less optimal than calling updateStackTransforms directly.
+     */
+    private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
+                                                            int stackScroll,
+                                                            int[] visibleRangeOut,
+                                                            boolean boundTranslationsToRect) {
+        ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
+        updateStackTransforms(taskTransforms, tasks, stackScroll, visibleRangeOut,
+                boundTranslationsToRect);
         return taskTransforms;
     }
 
@@ -237,14 +305,13 @@
             int[] visibleRange = mTmpVisibleRange;
             int stackScroll = getStackScroll();
             ArrayList<Task> tasks = mStack.getTasks();
-            ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll,
-                    visibleRange, false);
+            updateStackTransforms(mTaskTransforms, tasks, stackScroll, visibleRange, false);
 
             // Update the visible state of all the tasks
             int taskCount = tasks.size();
             for (int i = 0; i < taskCount; i++) {
                 Task task = tasks.get(i);
-                TaskViewTransform transform = taskTransforms.get(i);
+                TaskViewTransform transform = mTaskTransforms.get(i);
                 TaskView tv = getChildViewForTask(task);
 
                 if (transform.visible) {
@@ -255,7 +322,7 @@
                         if (mStackViewsAnimationDuration > 0 && i != 0) {
                             int fromIndex = (transform.t < 0) ? (visibleRange[0] - 1) :
                                     (visibleRange[1] + 1);
-                            tv.updateViewPropertiesToTaskTransform(null,
+                            tv.updateViewPropertiesToTaskTransform(
                                     getStackTransform(fromIndex, stackScroll), 0);
                         }
                     }
@@ -273,10 +340,10 @@
                 TaskView tv = (TaskView) getChildAt(i);
                 Task task = tv.getTask();
                 int taskIndex = mStack.indexOfTask(task);
-                if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
+                if (taskIndex < 0 || !mTaskTransforms.get(taskIndex).visible) {
                     mViewPool.returnViewToPool(tv);
                 } else {
-                    tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex),
+                    tv.updateViewPropertiesToTaskTransform(mTaskTransforms.get(taskIndex),
                             mStackViewsAnimationDuration);
                 }
             }
@@ -353,7 +420,7 @@
         mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
         mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
                 curScroll, 250));
-        mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().fastOutSlowInInterpolator);
+        mScrollAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
@@ -465,6 +532,20 @@
         }
     }
 
+    /** Animates a task view in this stack as it launches. */
+    public void animateOnLaunchingTask(TaskView tv, final Runnable r) {
+        // Hide each of the task bar dismiss buttons
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TaskView t = (TaskView) getChildAt(i);
+            if (t == tv) {
+                t.startLaunchTaskAnimation(r, true);
+            } else {
+                t.startLaunchTaskAnimation(null, false);
+            }
+        }
+    }
+
     /** Focuses the task at the specified index in the stack */
     void focusTask(int taskIndex, boolean scrollToNewPosition) {
         if (Console.Enabled) {
@@ -535,48 +616,31 @@
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
         if (Console.Enabled) {
+            int refCount = mHwLayersTrigger.getCount();
             Console.log(Constants.Log.UI.HwLayers,
                     "[TaskStackView|addHwLayersRefCount] refCount: " +
-                            mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
+                            refCount + "->" + (refCount + 1) + " " + reason);
         }
-        if (mHwLayersRefCount == 0) {
-            // Enable hw layers on each of the children
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                TaskView tv = (TaskView) getChildAt(i);
-                tv.enableHwLayers();
-            }
-        }
-        mHwLayersRefCount++;
+        mHwLayersTrigger.increment();
     }
 
     /** Decrements the hw layer requirement ref count and disables the hw layers when we don't
         need them anymore. */
     void decHwLayersRefCount(String reason) {
         if (Console.Enabled) {
+            int refCount = mHwLayersTrigger.getCount();
             Console.log(Constants.Log.UI.HwLayers,
                     "[TaskStackView|decHwLayersRefCount] refCount: " +
-                            mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
+                            refCount + "->" + (refCount - 1) + " " + reason);
         }
-        mHwLayersRefCount--;
-        if (mHwLayersRefCount == 0) {
-            // Disable hw layers on each of the children
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                TaskView tv = (TaskView) getChildAt(i);
-                tv.disableHwLayers();
-            }
-        } else if (mHwLayersRefCount < 0) {
-            new Throwable("Invalid hw layers ref count").printStackTrace();
-            Console.logError(getContext(), "Invalid HW layers ref count");
-        }
+        mHwLayersTrigger.decrement();
     }
 
     @Override
     public void computeScroll() {
         if (mScroller.computeScrollOffset()) {
             setStackScroll(mScroller.getCurrY());
-            invalidate();
+            invalidate(mStackRect);
 
             // If we just finished scrolling, then disable the hw layers
             if (mScroller.isFinished()) {
@@ -608,7 +672,6 @@
     @Override
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         if (Constants.DebugFlags.App.EnableTaskStackClipping) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
             TaskView tv = (TaskView) child;
             TaskView nextTv = null;
             TaskView tmpTv = null;
@@ -624,13 +687,13 @@
                 }
 
                 // Clip against the next view (if we aren't animating its alpha)
-                if (nextTv != null && nextTv.getAlpha() == 1f) {
+                if (nextTv != null) {
                     Rect curRect = tv.getClippingRect(mTmpRect);
                     Rect nextRect = nextTv.getClippingRect(mTmpRect2);
                     // The hit rects are relative to the task view, which needs to be offset by
                     // the system bar height
-                    curRect.offset(0, config.systemInsets.top);
-                    nextRect.offset(0, config.systemInsets.top);
+                    curRect.offset(0, mConfig.systemInsets.top);
+                    nextRect.offset(0, mConfig.systemInsets.top);
                     // Compute the clip region
                     Region clipRegion = new Region();
                     clipRegion.op(curRect, Region.Op.UNION);
@@ -652,7 +715,6 @@
         // Note: We let the stack view be the full height because we want the cards to go under the
         //       navigation bar if possible.  However, the stack rects which we use to calculate
         //       max scroll, etc. need to take the nav bar into account
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
 
         // Compute the stack rects
         mRect.set(0, 0, width, height);
@@ -660,8 +722,8 @@
         mStackRect.left += insetLeft;
         mStackRect.bottom -= insetBottom;
 
-        int widthPadding = (int) (config.taskStackWidthPaddingPct * mStackRect.width());
-        int heightPadding = config.taskStackTopPaddingPx;
+        int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
+        int heightPadding = mConfig.taskStackTopPaddingPx;
         if (Constants.DebugFlags.App.EnableSearchLayout) {
             mStackRect.top += heightPadding;
             mStackRect.left += widthPadding;
@@ -699,10 +761,9 @@
         }
 
         // Compute our stack/task rects
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
         Rect taskStackBounds = new Rect();
-        config.getTaskStackBounds(width, height, taskStackBounds);
-        computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom);
+        mConfig.getTaskStackBounds(width, height, taskStackBounds);
+        computeRects(width, height, taskStackBounds.left, mConfig.systemInsets.bottom);
 
         // Debug logging
         if (Constants.Log.UI.MeasureAndLayout) {
@@ -760,47 +821,69 @@
         }
 
         if (mAwaitingFirstLayout) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
-
-            // Update the focused task index to be the next item to the top task
-            if (config.launchedFromAltTab) {
-                focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
-            }
-
-            // Prepare the first view for its enter animation
-            if (config.launchedWithThumbnailAnimation) {
-                TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
-                if (tv != null) {
-                    tv.prepareAnimateOnEnterRecents();
-                }
-            }
-
             // Mark that we have completely the first layout
             mAwaitingFirstLayout = false;
 
+            // Start dozing
+            mDozeTrigger.startDozing();
+
+            // Prepare the first view for its enter animation
+            int offsetTopAlign = -mTaskRect.top;
+            int offscreenY = mRect.bottom - (mTaskRect.top - mRect.top);
+            for (int i = childCount - 1; i >= 0; i--) {
+                TaskView tv = (TaskView) getChildAt(i);
+                tv.prepareEnterRecentsAnimation((i == (getChildCount() - 1)), offsetTopAlign,
+                        offscreenY, mTaskRect);
+            }
+
             // If the enter animation started already and we haven't completed a layout yet, do the
             // enter animation now
             if (mStartEnterAnimationRequestedAfterLayout) {
-                startOnEnterAnimation();
+                startEnterRecentsAnimation(mStartEnterAnimationContext);
+                mStartEnterAnimationRequestedAfterLayout = false;
+                mStartEnterAnimationContext = null;
+            }
+
+            // Update the focused task index to be the next item to the top task
+            if (mConfig.launchedWithAltTab) {
+                focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
             }
         }
     }
 
     /** Requests this task stacks to start it's enter-recents animation */
-    public void startOnEnterAnimation() {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        if (!config.launchedWithThumbnailAnimation) return;
-
+    public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
         // If we are still waiting to layout, then just defer until then
         if (mAwaitingFirstLayout) {
             mStartEnterAnimationRequestedAfterLayout = true;
+            mStartEnterAnimationContext = ctx;
             return;
         }
 
-        // Animate the task bar of the first task view
-        TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
-        if (tv != null) {
-            tv.animateOnEnterRecents();
+        // Animate all the task views into view
+        ctx.taskRect = mTaskRect;
+        ctx.stackRectSansPeek = mStackRectSansPeek;
+        int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            TaskView tv = (TaskView) getChildAt(i);
+            TaskViewTransform transform = getStackTransform(mStack.indexOfTask(tv.getTask()),
+                    getStackScroll());
+            ctx.stackViewIndex = i;
+            ctx.stackViewCount = childCount;
+            ctx.isFrontMost = (i == (getChildCount() - 1));
+            ctx.transform = transform;
+            tv.startEnterRecentsAnimation(ctx);
+        }
+    }
+
+    /** Requests this task stacks to start it's exit-recents animation. */
+    public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+        // Animate all the task views into view
+        ctx.offscreenTranslationY = mRect.bottom - (mTaskRect.top - mRect.top);
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TaskView tv = (TaskView) getChildAt(i);
+            tv.startExitToHomeAnimation(ctx);
         }
     }
 
@@ -814,6 +897,15 @@
         return isTransformedTouchPointInView(x, y, child, null);
     }
 
+    /** Pokes the dozer on user interaction. */
+    void onUserInteraction() {
+        // If the dozer is not running, then either we have not yet laid out, or it has already
+        // fallen asleep, so just let it rest.
+        if (mDozeTrigger.isDozing()) {
+            mDozeTrigger.poke();
+        }
+    }
+
     /**** TaskStackCallbacks Implementation ****/
 
     @Override
@@ -863,8 +955,7 @@
                         ArrayList<TaskViewTransform> curTaskTransforms,
                         ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms,
                         HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
-                        ArrayList<TaskView> childrenToRemoveOut,
-                        RecentsConfiguration config) {
+                        ArrayList<TaskView> childrenToRemoveOut) {
         // Animate all of the existing views out of view (if they are not in the visible range in
         // the new stack) or to their final positions in the new stack
         int movement = 0;
@@ -894,7 +985,7 @@
             childViewTransformsOut.put(tv, new Pair(0, toTransform));
         }
         return Utilities.calculateTranslationAnimationDuration(movement,
-                config.filteringCurrentViewsMinAnimDuration);
+                mConfig.filteringCurrentViewsMinAnimDuration);
     }
 
     /**
@@ -903,8 +994,7 @@
      */
     int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks,
                          ArrayList<TaskViewTransform> taskTransforms,
-                         HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
-                         RecentsConfiguration config) {
+                         HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut) {
         int offset = 0;
         int movement = 0;
         int taskCount = tasks.size();
@@ -920,7 +1010,7 @@
                     // Compose a new transform to fade and slide the new task in
                     TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
                     tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
-                    tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+                    tv.updateViewPropertiesToTaskTransform(fromTransform, 0);
 
                     int startDelay = offset *
                             Constants.Values.TaskStackView.FilterStartDelay;
@@ -934,7 +1024,7 @@
             }
         }
         return Utilities.calculateTranslationAnimationDuration(movement,
-                config.filteringNewViewsMinAnimDuration);
+                mConfig.filteringNewViewsMinAnimDuration);
     }
 
     /** Orchestrates the animations of the current child views and any new views. */
@@ -942,22 +1032,20 @@
                               ArrayList<TaskViewTransform> curTaskTransforms,
                               final ArrayList<Task> tasks,
                               final ArrayList<TaskViewTransform> taskTransforms) {
-        final RecentsConfiguration config = RecentsConfiguration.getInstance();
-
         // Calculate the transforms to animate out all the existing views if they are not in the
         // new visible range (or to their final positions in the stack if they are)
         final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
         final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms =
                 new HashMap<TaskView, Pair<Integer, TaskViewTransform>>();
         int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks,
-                taskTransforms, childViewTransforms, childrenToRemove, config);
+                taskTransforms, childViewTransforms, childrenToRemove);
 
         // If all the current views are in the visible range of the new stack, then don't wait for
         // views to animate out and animate all the new views into their place
         final boolean unifyNewViewAnimation = childrenToRemove.isEmpty();
         if (unifyNewViewAnimation) {
             int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms,
-                    childViewTransforms, config);
+                    childViewTransforms);
             duration = Math.max(duration, inDuration);
         }
 
@@ -981,17 +1069,17 @@
                                     // For views that are not already visible, animate them in
                                     childViewTransforms.clear();
                                     int duration = getEnterTransformsForFilterAnimation(tasks,
-                                            taskTransforms, childViewTransforms, config);
+                                            taskTransforms, childViewTransforms);
                                     for (final TaskView tv : childViewTransforms.keySet()) {
                                         Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
                                         tv.animate().setStartDelay(t.first);
-                                        tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+                                        tv.updateViewPropertiesToTaskTransform(t.second, duration);
                                     }
                                 }
                             }
                         }
                     });
-            tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+            tv.updateViewPropertiesToTaskTransform(t.second, duration);
         }
     }
 
@@ -1103,6 +1191,11 @@
         // but just in case, re-enable it here
         tv.setClipViewInStack(true);
 
+        // If the doze trigger has already fired, then update the state for this task view
+        if (mDozeTrigger.hasTriggered()) {
+            tv.setNoUserInteractionState();
+        }
+
         // Add/attach the view to the hierarchy
         if (Console.Enabled) {
             Console.log(Constants.Log.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
@@ -1119,7 +1212,7 @@
         }
 
         // Enable hw layers on this view if hw layers are enabled on the stack
-        if (mHwLayersRefCount > 0) {
+        if (mHwLayersTrigger.getCount() > 0) {
             tv.enableHwLayers();
         }
     }
@@ -1188,7 +1281,6 @@
 
     @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--) {
@@ -1197,7 +1289,7 @@
                 TaskView tv = getChildViewForTask(t);
                 if (tv != null) {
                     // For visible children, defer removing the task until after the animation
-                    tv.animateRemoval(new Runnable() {
+                    tv.startDeleteTaskAnimation(new Runnable() {
                         @Override
                         public void run() {
                             mStack.removeTask(t);
@@ -1494,7 +1586,7 @@
                             mSv.mMinScroll, mSv.mMaxScroll,
                             0, overscrollRange);
                     // Invalidate to kick off computeScroll
-                    mSv.invalidate();
+                    mSv.invalidate(mSv.mStackRect);
                 } else if (mSv.isScrollOutOfBounds()) {
                     // Animate the scroll back into bounds
                     // XXX: Make this animation a function of the velocity OR distance
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
index 8a9250a..c2b2094 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
@@ -17,15 +17,23 @@
 package com.android.systemui.recents.views;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.ImageView;
 import com.android.systemui.recents.model.Task;
 
 
 /** The task thumbnail view */
 public class TaskThumbnailView extends ImageView {
+
     Task mTask;
 
+    // Task bar clipping
+    Rect mClipRect;
+    boolean mClipTaskBar = true;
+
     public TaskThumbnailView(Context context) {
         this(context, null);
     }
@@ -43,14 +51,42 @@
         setScaleType(ScaleType.FIT_XY);
     }
 
+    @Override
+    public void draw(Canvas canvas) {
+        if (mClipTaskBar && (mClipRect != null)) {
+            int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+            canvas.clipRect(mClipRect);
+            super.draw(canvas);
+            canvas.restoreToCount(restoreCount);
+        } else {
+            super.draw(canvas);
+        }
+    }
+
+    /** Updates the clip rect based on the given task bar. */
+    void updateTaskBarClip(View taskBar) {
+        // If mClipTaskBar is unset first, then we don't bother setting mTaskBar
+        if (mClipTaskBar) {
+            int top = (int) Math.max(0, taskBar.getTranslationY() +
+                    taskBar.getMeasuredHeight() - 1);
+            mClipRect = new Rect(0, top, getMeasuredWidth(), getMeasuredHeight());
+            invalidate(0, 0, taskBar.getMeasuredWidth(), taskBar.getMeasuredHeight() + 1);
+        }
+    }
+
+    /** Disables the task bar clipping. */
+    void disableClipTaskBarView() {
+        mClipTaskBar = false;
+        if (mClipRect != null) {
+            invalidate(0, 0, mClipRect.width(), mClipRect.top);
+        }
+    }
+
     /** Binds the thumbnail view to the task */
     void rebindToTask(Task t, boolean animate) {
         mTask = t;
         if (t.thumbnail != null) {
             setImageBitmap(t.thumbnail);
-            if (animate) {
-                // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
-            }
         }
     }
 
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 632c816..09dc1c8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -28,9 +29,11 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
+import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.model.Task;
@@ -45,10 +48,10 @@
         public void onTaskAppInfoClicked(TaskView tv);
         public void onTaskFocused(TaskView tv);
         public void onTaskDismissed(TaskView tv);
-
-        // public void onTaskViewReboundToTask(TaskView tv, Task t);
     }
 
+    RecentsConfiguration mConfig;
+
     int mDim;
     int mMaxDim;
     TimeInterpolator mDimInterpolator = new AccelerateInterpolator();
@@ -59,11 +62,33 @@
     boolean mClipViewInStack;
     Point mLastTouchDown = new Point();
     Path mRoundedRectClipPath = new Path();
+    Rect mTmpRect = new Rect();
 
     TaskThumbnailView mThumbnailView;
     TaskBarView mBarView;
     TaskViewCallbacks mCb;
 
+    // Optimizations
+    ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    updateDimOverlayFromScale();
+                }
+            };
+    Runnable mEnableThumbnailClip = new Runnable() {
+        @Override
+        public void run() {
+            mThumbnailView.updateTaskBarClip(mBarView);
+        }
+    };
+    Runnable mDisableThumbnailClip = new Runnable() {
+        @Override
+        public void run() {
+            mThumbnailView.disableClipTaskBarView();
+        }
+    };
+
 
     public TaskView(Context context) {
         this(context, null);
@@ -79,20 +104,21 @@
 
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mConfig = RecentsConfiguration.getInstance();
         setWillNotDraw(false);
+        setDim(getDim());
     }
 
     @Override
     protected void onFinishInflate() {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mMaxDim = config.taskStackMaxDim;
+        mMaxDim = mConfig.taskStackMaxDim;
 
         // By default, all views are clipped to other views in their stack
         mClipViewInStack = true;
 
         // Bind the views
-        mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
         mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
+        mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
 
         if (mTaskDataLoaded) {
             onTaskDataLoaded(false);
@@ -104,8 +130,7 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
         // Update the rounded rect clip path
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        float radius = config.taskViewRoundedCornerRadiusPx;
+        float radius = mConfig.taskViewRoundedCornerRadiusPx;
         mRoundedRectClipPath.reset();
         mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
                 radius, radius, Path.Direction.CW);
@@ -113,7 +138,7 @@
         // Update the outline
         Outline o = new Outline();
         o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight() -
-                config.taskViewShadowOutlineBottomInsetPx, radius);
+                mConfig.taskViewShadowOutlineBottomInsetPx, radius);
         setOutline(o);
     }
 
@@ -139,54 +164,64 @@
     }
 
     /** Synchronizes this view's properties with the task's transform */
-    void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
-                                             TaskViewTransform toTransform, int duration) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        int minZ = config.taskViewTranslationZMinPx;
-        int incZ = config.taskViewTranslationZIncrementPx;
+    void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) {
+        if (Console.Enabled) {
+            Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]",
+                    "duration: " + duration, Console.AnsiPurple);
+        }
 
         // Update the bar view
-        mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
+        mBarView.updateViewPropertiesToTaskTransform(toTransform, duration);
 
-        // Update this task view
+        // Check to see if any properties have changed, and update the task view
         if (duration > 0) {
-            if (animateFromTransform != null) {
-                setTranslationY(animateFromTransform.translationY);
-                if (Constants.DebugFlags.App.EnableShadows) {
-                    setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
-                }
-                setScaleX(animateFromTransform.scale);
-                setScaleY(animateFromTransform.scale);
-                setAlpha(animateFromTransform.alpha);
+            ViewPropertyAnimator anim = animate();
+            boolean useLayers = false;
+
+            // Animate to the final state
+            if (toTransform.hasTranslationYChangedFrom(getTranslationY())) {
+                anim.translationY(toTransform.translationY);
             }
-            if (Constants.DebugFlags.App.EnableShadows) {
-                animate().translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+            if (Constants.DebugFlags.App.EnableShadows &&
+                    toTransform.hasTranslationZChangedFrom(getTranslationZ())) {
+                anim.translationZ(toTransform.translationZ);
             }
-            animate().translationY(toTransform.translationY)
-                    .scaleX(toTransform.scale)
+            if (toTransform.hasScaleChangedFrom(getScaleX())) {
+                anim.scaleX(toTransform.scale)
                     .scaleY(toTransform.scale)
-                    .alpha(toTransform.alpha)
-                    .setDuration(duration)
-                    .setInterpolator(config.fastOutSlowInInterpolator)
-                    .withLayer()
-                    .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                        @Override
-                        public void onAnimationUpdate(ValueAnimator animation) {
-                            updateDimOverlayFromScale();
-                        }
-                    })
-                    .start();
-        } else {
-            setTranslationY(toTransform.translationY);
-            if (Constants.DebugFlags.App.EnableShadows) {
-                setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+                    .setUpdateListener(mUpdateDimListener);
+                useLayers = true;
             }
-            setScaleX(toTransform.scale);
-            setScaleY(toTransform.scale);
-            setAlpha(toTransform.alpha);
+            if (toTransform.hasAlphaChangedFrom(getAlpha())) {
+                // Use layers if we animate alpha
+                anim.alpha(toTransform.alpha);
+                useLayers = true;
+            }
+            if (useLayers) {
+                anim.withLayer();
+            }
+            anim.setStartDelay(0)
+                .setDuration(duration)
+                .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                .start();
+        } else {
+            // Set the changed properties
+            if (toTransform.hasTranslationYChangedFrom(getTranslationY())) {
+                setTranslationY(toTransform.translationY);
+            }
+            if (Constants.DebugFlags.App.EnableShadows &&
+                    toTransform.hasTranslationZChangedFrom(getTranslationZ())) {
+                setTranslationZ(toTransform.translationZ);
+            }
+            if (toTransform.hasScaleChangedFrom(getScaleX())) {
+                setScaleX(toTransform.scale);
+                setScaleY(toTransform.scale);
+                updateDimOverlayFromScale();
+            }
+            if (toTransform.hasAlphaChangedFrom(getAlpha())) {
+                setAlpha(toTransform.alpha);
+            }
         }
-        updateDimOverlayFromScale();
-        invalidate();
     }
 
     /** Resets this view's properties */
@@ -199,6 +234,7 @@
         setScaleX(1f);
         setScaleY(1f);
         setAlpha(1f);
+        setDim(0);
         invalidate();
     }
 
@@ -223,64 +259,174 @@
 
     /** Prepares this task view for the enter-recents animations.  This is called earlier in the
      * first layout because the actual animation into recents may take a long time. */
-    public void prepareAnimateOnEnterRecents() {
-        mBarView.setVisibility(View.INVISIBLE);
+    public void prepareEnterRecentsAnimation(boolean isTaskViewFrontMost, int offsetY, int offscreenY,
+                                             Rect taskRect) {
+        if (mConfig.launchedFromAppWithScreenshot) {
+            if (isTaskViewFrontMost) {
+                // Hide the task view as we are going to animate the full screenshot into view
+                // and then replace it with this view once we are done
+                setVisibility(View.INVISIBLE);
+                // Also hide the front most task bar view so we can animate it in
+                mBarView.prepareEnterRecentsAnimation();
+            } else {
+                // Top align the task views
+                setTranslationY(offsetY);
+                setScaleX(1f);
+                setScaleY(1f);
+            }
+
+        } else if (mConfig.launchedFromAppWithThumbnail) {
+            if (isTaskViewFrontMost) {
+                // Hide the front most task bar view so we can animate it in
+                mBarView.prepareEnterRecentsAnimation();
+                // Set the dim to 0 so we can animate it in
+                setDim(0);
+            }
+
+        } else if (mConfig.launchedFromHome) {
+            // Move the task view off screen (below) so we can animate it in
+            setTranslationY(offscreenY);
+            setTranslationZ(0);
+            setScaleX(1f);
+            setScaleY(1f);
+        }
     }
 
     /** Animates this task view as it enters recents */
-    public void animateOnEnterRecents() {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mBarView.setVisibility(View.VISIBLE);
-        mBarView.setTranslationY(-mBarView.getMeasuredHeight());
-        mBarView.animate()
-                .translationY(0)
-                .setStartDelay(config.taskBarEnterAnimDelay)
-                .setInterpolator(config.fastOutSlowInInterpolator)
-                .setDuration(config.taskBarEnterAnimDuration)
+    public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
+        TaskViewTransform transform = ctx.transform;
+
+        if (mConfig.launchedFromAppWithScreenshot) {
+            if (ctx.isFrontMost) {
+                // Animate the full screenshot down first, before swapping with this task view
+                ctx.fullScreenshot.animateOnEnterRecents(ctx, new Runnable() {
+                    @Override
+                    public void run() {
+                        // Animate the task bar of the first task view
+                        mBarView.startEnterRecentsAnimation(0, mEnableThumbnailClip);
+                        setVisibility(View.VISIBLE);
+                    }
+                });
+            } else {
+                // Animate the tasks down behind the full screenshot
+                animate()
+                        .scaleX(transform.scale)
+                        .scaleY(transform.scale)
+                        .translationY(transform.translationY)
+                        .setStartDelay(0)
+                        .setUpdateListener(null)
+                        .setInterpolator(mConfig.linearOutSlowInInterpolator)
+                        .setDuration(475)
+                        .withLayer()
+                        .withEndAction(mEnableThumbnailClip)
+                        .start();
+            }
+
+        } else if (mConfig.launchedFromAppWithThumbnail) {
+            if (ctx.isFrontMost) {
+                // Animate the task bar of the first task view
+                mBarView.startEnterRecentsAnimation(mConfig.taskBarEnterAnimDelay, mEnableThumbnailClip);
+
+                // Animate the dim into view as well
+                ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", getDimOverlayFromScale());
+                anim.setStartDelay(mConfig.taskBarEnterAnimDelay);
+                anim.setDuration(mConfig.taskBarEnterAnimDuration);
+                anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+                anim.start();
+            } else {
+                mEnableThumbnailClip.run();
+            }
+
+        } else if (mConfig.launchedFromHome) {
+            // Animate the tasks up
+            int frontIndex = (ctx.stackViewCount - ctx.stackViewIndex - 1);
+            int delay = mConfig.taskBarEnterAnimDelay +
+                    frontIndex * mConfig.taskViewEnterFromHomeDelay;
+            animate()
+                    .scaleX(transform.scale)
+                    .scaleY(transform.scale)
+                    .translationY(transform.translationY)
+                    .translationZ(transform.translationZ)
+                    .setStartDelay(delay)
+                    .setUpdateListener(null)
+                    .setInterpolator(mConfig.quintOutInterpolator)
+                    .setDuration(mConfig.taskViewEnterFromHomeDuration)
+                    .withLayer()
+                    .withEndAction(mEnableThumbnailClip)
+                    .start();
+        }
+    }
+
+    /** Animates this task view as it leaves recents by pressing home. */
+    public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+        animate()
+                .translationY(ctx.offscreenTranslationY)
+                .setStartDelay(0)
+                .setUpdateListener(null)
+                .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                .setDuration(mConfig.taskViewExitToHomeDuration)
                 .withLayer()
+                .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
                 .start();
+        ctx.postAnimationTrigger.increment();
     }
 
     /** Animates this task view as it exits recents */
-    public void animateOnLeavingRecents(final Runnable r) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mBarView.animate()
-            .translationY(-mBarView.getMeasuredHeight())
+    public void startLaunchTaskAnimation(final Runnable r, boolean isLaunchingTask) {
+        if (isLaunchingTask) {
+            // Disable the thumbnail clip and animate the bar out
+            mBarView.startLaunchTaskAnimation(mDisableThumbnailClip, r);
+
+            // Animate the dim
+            if (mDim > 0) {
+                ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
+                anim.setDuration(mConfig.taskBarExitAnimDuration);
+                anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+                anim.start();
+            }
+        } else {
+            // Hide the dismiss button
+            mBarView.startLaunchTaskDismissAnimation();
+        }
+    }
+
+    /** Animates the deletion of this task view */
+    public void startDeleteTaskAnimation(final Runnable r) {
+        // Disabling clipping with the stack while the view is animating away
+        setClipViewInStack(false);
+
+        animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
+            .alpha(0f)
             .setStartDelay(0)
-            .setInterpolator(config.fastOutLinearInInterpolator)
-            .setDuration(config.taskBarExitAnimDuration)
+            .setUpdateListener(null)
+            .setInterpolator(mConfig.fastOutSlowInInterpolator)
+            .setDuration(mConfig.taskViewRemoveAnimDuration)
             .withLayer()
             .withEndAction(new Runnable() {
                 @Override
                 public void run() {
-                    post(r);
+                    // We just throw this into a runnable because starting a view property
+                    // animation using layers can cause inconsisten results if we try and
+                    // update the layers while the animation is running.  In some cases,
+                    // the runnabled passed in may start an animation which also uses layers
+                    // so we defer all this by posting this.
+                    r.run();
+
+                    // Re-enable clipping with the stack (we will reuse this view)
+                    setClipViewInStack(true);
                 }
             })
             .start();
     }
 
-    /** Animates the deletion of this task view */
-    public void animateRemoval(final Runnable r) {
-        // Disabling clipping with the stack while the view is animating away
-        setClipViewInStack(false);
+    /** Animates this task view if the user does not interact with the stack after a certain time. */
+    public void startNoUserInteractionAnimation() {
+        mBarView.startNoUserInteractionAnimation();
+    }
 
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        animate().translationX(config.taskViewRemoveAnimTranslationXPx)
-            .alpha(0f)
-            .setStartDelay(0)
-            .setInterpolator(config.fastOutSlowInInterpolator)
-            .setDuration(config.taskViewRemoveAnimDuration)
-            .withLayer()
-            .withEndAction(new Runnable() {
-                @Override
-                public void run() {
-                    post(r);
-
-                    // Re-enable clipping with the stack (we will reuse this view)
-                    setClipViewInStack(false);
-                }
-            })
-            .start();
+    /** Mark this task view that the user does has not interacted with the stack after a certain time. */
+    public void setNoUserInteractionState() {
+        mBarView.setNoUserInteractionState();
     }
 
     /** Returns the rect we want to clip (it may not be the full rect) */
@@ -295,11 +441,13 @@
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
         mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        mBarView.enableHwLayers();
     }
 
     /** Disable the hw layers on this task view */
     void disableHwLayers() {
         mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
+        mBarView.disableHwLayers();
     }
 
     /**
@@ -307,7 +455,7 @@
      * view.
      */
     boolean shouldClipViewInStack() {
-        return mClipViewInStack;
+        return mClipViewInStack && (getVisibility() == View.VISIBLE);
     }
 
     /** Sets whether this view should be clipped, or clipped against. */
@@ -315,28 +463,44 @@
         if (clip != mClipViewInStack) {
             mClipViewInStack = clip;
             if (getParent() instanceof View) {
-                Rect r = new Rect();
-                getHitRect(r);
-                ((View) getParent()).invalidate(r);
+                getHitRect(mTmpRect);
+                ((View) getParent()).invalidate(mTmpRect);
             }
         }
     }
 
-    /** Update the dim as a function of the scale of this view. */
-    void updateDimOverlayFromScale() {
+    /** Returns the current dim. */
+    public void setDim(int dim) {
+        mDim = dim;
+        postInvalidateOnAnimation();
+    }
+
+    /** Returns the current dim. */
+    public int getDim() {
+        return mDim;
+    }
+
+    /** Compute the dim as a function of the scale of this view. */
+    int getDimOverlayFromScale() {
         float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
         float scaleRange = 1f - minScale;
         float dim = (1f - getScaleX()) / scaleRange;
         dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
-        mDim = Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
+        return Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
+    }
+
+    /** Update the dim as a function of the scale of this view. */
+    void updateDimOverlayFromScale() {
+        setDim(getDimOverlayFromScale());
     }
 
     @Override
     public void draw(Canvas canvas) {
+        int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
         // Apply the rounded rect clip path on the whole view
         canvas.clipPath(mRoundedRectClipPath);
-
         super.draw(canvas);
+        canvas.restoreToCount(restoreCount);
 
         // Apply the dim if necessary
         if (mDim > 0) {
@@ -393,8 +557,7 @@
             mBarView.mApplicationIcon.setOnClickListener(this);
             mBarView.mDismissButton.setOnClickListener(this);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
-                RecentsConfiguration config = RecentsConfiguration.getInstance();
-                if (config.developerOptionsEnabled) {
+                if (mConfig.developerOptionsEnabled) {
                     mBarView.mApplicationIcon.setOnLongClickListener(this);
                 }
             }
@@ -426,7 +589,7 @@
         } else if (v == mBarView.mDismissButton) {
             // Animate out the view and call the callback
             final TaskView tv = this;
-            animateRemoval(new Runnable() {
+            startDeleteTaskAnimation(new Runnable() {
                 @Override
                 public void run() {
                     mCb.onTaskDismissed(tv);
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 e6391a8..6c420e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -22,6 +22,7 @@
 /* The transform state for a task view */
 public class TaskViewTransform {
     public int translationY = 0;
+    public int translationZ = 0;
     public float scale = 1f;
     public float alpha = 1f;
     public float dismissAlpha = 1f;
@@ -35,6 +36,7 @@
 
     public TaskViewTransform(TaskViewTransform o) {
         translationY = o.translationY;
+        translationZ = o.translationZ;
         scale = o.scale;
         alpha = o.alpha;
         dismissAlpha = o.dismissAlpha;
@@ -43,9 +45,27 @@
         t = o.t;
     }
 
+    /** Convenience functions to compare against current property values */
+    public boolean hasAlphaChangedFrom(float v) {
+        return (Float.compare(alpha, v) != 0);
+    }
+    public boolean hasDismissAlphaChangedFrom(float v) {
+        return (Float.compare(dismissAlpha, v) != 0);
+    }
+    public boolean hasScaleChangedFrom(float v) {
+        return (Float.compare(scale, v) != 0);
+    }
+    public boolean hasTranslationYChangedFrom(float v) {
+        return (Float.compare(translationY, v) != 0);
+    }
+    public boolean hasTranslationZChangedFrom(float v) {
+        return (Float.compare(translationZ, v) != 0);
+    }
+
     @Override
     public String toString() {
-        return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
-                " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha;
+        return "TaskViewTransform y: " + translationY + " z: " + translationZ + " scale: " + scale +
+                " alpha: " + alpha + " visible: " + visible + " rect: " + rect +
+                " dismissAlpha: " + dismissAlpha;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
new file mode 100644
index 0000000..b5e8ffd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -0,0 +1,60 @@
+/*
+ * 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.views;
+
+import android.graphics.Rect;
+import com.android.systemui.recents.ReferenceCountedTrigger;
+
+/* Common code related to view animations */
+public class ViewAnimation {
+
+    /* The animation context for a task view animation into Recents */
+    public static class TaskViewEnterContext {
+        // The full screenshot view that we are animating down
+        FullScreenTransitionView fullScreenshot;
+        // The transform of the current task view
+        TaskViewTransform transform;
+        // The stack rect that the transform is relative to
+        Rect stackRectSansPeek;
+        // The task rect
+        Rect taskRect;
+        // The view index of the current task view
+        int stackViewIndex;
+        // The total number of task views
+        int stackViewCount;
+        // Whether this is the front most task view
+        boolean isFrontMost;
+
+        public TaskViewEnterContext(FullScreenTransitionView fss) {
+            fullScreenshot = fss;
+        }
+    }
+
+    /* The animation context for a task view animation out of Recents */
+    public static class TaskViewExitContext {
+        // A trigger to run some logic when all the animations complete.  This works around the fact
+        // that it is difficult to coordinate ViewPropertyAnimators
+        ReferenceCountedTrigger postAnimationTrigger;
+        // The translationY to apply to a TaskView to move it off screen
+        int offscreenTranslationY;
+
+        public TaskViewExitContext(ReferenceCountedTrigger t) {
+            postAnimationTrigger = t;
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index a770f58..80e85f9 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -34,6 +34,7 @@
 
 public class BrightnessController implements ToggleSlider.Listener {
     private static final String TAG = "StatusBar.BrightnessController";
+    private static final boolean SHOW_AUTOMATIC_ICON = false;
 
     /**
      * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
@@ -232,7 +233,7 @@
 
     private void updateIcon(boolean automatic) {
         if (mIcon != null) {
-            mIcon.setImageResource(automatic ?
+            mIcon.setImageResource(automatic && SHOW_AUTOMATIC_ICON ?
                     com.android.systemui.R.drawable.ic_qs_brightness_auto_on :
                     com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
index d67e7cb..a3b10f2 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
@@ -21,8 +21,16 @@
 import android.app.ActivityManagerNative;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -43,15 +51,18 @@
 /**
  * A quick and dirty view to show a user switcher.
  */
-public class UserSwitcherHostView extends FrameLayout implements ListView.OnItemClickListener {
+public class UserSwitcherHostView extends FrameLayout
+        implements ListView.OnItemClickListener, View.OnClickListener {
 
     private static final String TAG = "UserSwitcherDialog";
 
     private ArrayList<UserInfo> mUserInfo = new ArrayList<UserInfo>();
+    private UserInfo mGuestUser;
     private Adapter mAdapter = new Adapter();
     private UserManager mUserManager;
     private Runnable mFinishRunnable;
     private ListView mListView;
+    private boolean mGuestUserEnabled;
 
     public UserSwitcherHostView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -60,6 +71,9 @@
             return;
         }
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+
+        mGuestUserEnabled = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.GUEST_USER_ENABLED, 0) == 1;
     }
 
     public UserSwitcherHostView(Context context, AttributeSet attrs) {
@@ -80,7 +94,39 @@
 
     @Override
     public void onItemClick(AdapterView<?> l, View v, int position, long id) {
-        int userId = mAdapter.getItem(position).id;
+        // Last item is the guest
+        if (position == mUserInfo.size()) {
+            postDelayed(new Runnable() {
+                public void run() {
+                    switchToGuestUser();
+                }
+            }, 100);
+        } else {
+            final int userId = mAdapter.getItem(position).id;
+            postDelayed(new Runnable() {
+                public void run() {
+                    switchUser(userId);
+                }
+            }, 100);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        // Delete was clicked
+        postDelayed(new Runnable() {
+            public void run() {
+                if (mGuestUser != null) {
+                    switchUser(0);
+                    mUserManager.removeUser(mGuestUser.id);
+                    mGuestUser = null;
+                    refreshUsers();
+                }
+            }
+        }, 100);
+    }
+
+    private void switchUser(int userId) {
         try {
             WindowManagerGlobal.getWindowManagerService().lockNow(null);
             ActivityManagerNative.getDefault().switchUser(userId);
@@ -90,6 +136,15 @@
         }
     }
 
+    private void switchToGuestUser() {
+        if (mGuestUser == null) {
+            // No guest user. Create one.
+            mGuestUser = mUserManager.createGuest(mContext, 
+                    mContext.getResources().getString(R.string.guest_nickname));
+        }
+        switchUser(mGuestUser.id);
+    }
+
     private void finish() {
         if (mFinishRunnable != null) {
             mFinishRunnable.run();
@@ -119,9 +174,12 @@
 
     public void refreshUsers() {
         mUserInfo.clear();
+        mGuestUser = null;
         List<UserInfo> users = mUserManager.getUsers(true);
         for (UserInfo user : users) {
-            if (!user.isManagedProfile()) {
+            if (user.isGuest()) {
+                mGuestUser = user;
+            } else if (!user.isManagedProfile()) {
                 mUserInfo.add(user);
             }
         }
@@ -132,17 +190,25 @@
 
         @Override
         public int getCount() {
-            return mUserInfo.size();
+            return mUserInfo.size() + (mGuestUserEnabled ? 1 : 0);
         }
 
         @Override
         public UserInfo getItem(int position) {
-            return mUserInfo.get(position);
+            if (position < mUserInfo.size()) {
+                return mUserInfo.get(position);
+            } else {
+                return mGuestUser;
+            }
         }
 
         @Override
         public long getItemId(int position) {
-            return getItem(position).serialNumber;
+            if (position < mUserInfo.size()) {
+                return getItem(position).serialNumber;
+            } else {
+                return mGuestUser != null ? mGuestUser.serialNumber : -1;
+            }
         }
 
         @Override
@@ -161,18 +227,46 @@
             ViewHolder h = new ViewHolder();
             h.name = (TextView) v.findViewById(R.id.user_name);
             h.picture = (ImageView) v.findViewById(R.id.user_picture);
+            h.delete = (ImageView) v.findViewById(R.id.user_delete);
             v.setTag(h);
             return v;
         }
 
         private void bindView(ViewHolder h, UserInfo item) {
-            h.name.setText(item.name);
-            h.picture.setImageBitmap(mUserManager.getUserIcon(item.id));
+            if (item != null) {
+                h.name.setText(item.name);
+                h.picture.setImageBitmap(circularClip(mUserManager.getUserIcon(item.id)));
+                h.delete.setVisibility(item.isGuest() ? View.VISIBLE : View.GONE);
+                h.delete.setOnClickListener(UserSwitcherHostView.this);
+                if (item.isGuest()) {
+                    h.picture.setImageResource(R.drawable.ic_account_circle);
+                }
+            } else {
+                h.name.setText(R.string.guest_new_guest);
+                h.picture.setImageResource(R.drawable.ic_account_circle);
+                h.delete.setVisibility(View.GONE);
+            }
+        }
+
+        private Bitmap circularClip(Bitmap input) {
+            if (input == null) {
+                return null;
+            }
+            Bitmap output = Bitmap.createBitmap(input.getWidth(),
+                    input.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(output);
+            final Paint paint = new Paint();
+            paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+            paint.setAntiAlias(true);
+            canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2,
+                    paint);
+            return output;
         }
 
         class ViewHolder {
             TextView name;
             ImageView picture;
+            ImageView delete;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index b91e129..8d19f50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -158,7 +158,7 @@
     private final Runnable mTapTimeoutRunnable = new Runnable() {
         @Override
         public void run() {
-            makeInactive();
+            makeInactive(true /* animate */);
         }
     };
 
@@ -183,7 +183,7 @@
                 break;
             case MotionEvent.ACTION_MOVE:
                 if (!isWithinTouchSlop(event)) {
-                    makeInactive();
+                    makeInactive(true /* animate */);
                     return false;
                 }
                 break;
@@ -193,14 +193,17 @@
                         makeActive();
                         postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
                     } else {
-                        performClick();
+                        boolean performed = performClick();
+                        if (performed) {
+                            removeCallbacks(mTapTimeoutRunnable);
+                        }
                     }
                 } else {
-                    makeInactive();
+                    makeInactive(true /* animate */);
                 }
                 break;
             case MotionEvent.ACTION_CANCEL:
-                makeInactive();
+                makeInactive(true /* animate */);
                 break;
             default:
                 break;
@@ -257,10 +260,14 @@
     /**
      * Cancels the hotspot and makes the notification inactive.
      */
-    private void makeInactive() {
+    public void makeInactive(boolean animate) {
         if (mActivated) {
             if (mDimmed) {
-                startActivateAnimation(true /* reverse */);
+                if (animate) {
+                    startActivateAnimation(true /* reverse */);
+                } else {
+                    mBackgroundNormal.setVisibility(View.INVISIBLE);
+                }
             }
             mActivated = false;
         }
@@ -351,6 +358,7 @@
             mBackgroundDimmed.setVisibility(View.INVISIBLE);
             mBackgroundNormal.setVisibility(View.VISIBLE);
             mBackgroundNormal.setAlpha(1f);
+            removeCallbacks(mTapTimeoutRunnable);
         }
     }
 
@@ -581,7 +589,7 @@
     }
 
     public interface OnActivatedListener {
-        void onActivated(View view);
-        void onActivationReset(View view);
+        void onActivated(ActivatableNotificationView view);
+        void onActivationReset(ActivatableNotificationView view);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 508c34e..20684a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -48,7 +48,7 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
@@ -80,17 +80,17 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
+import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.Locale;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 
 public abstract class BaseStatusBar extends SystemUI implements
-        CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener {
+        CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
+        RecentsComponent.Callbacks {
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
@@ -106,6 +106,7 @@
     protected static final int MSG_SHOW_HEADS_UP = 1026;
     protected static final int MSG_HIDE_HEADS_UP = 1027;
     protected static final int MSG_ESCALATE_HEADS_UP = 1028;
+    protected static final int MSG_DECAY_HEADS_UP = 1029;
 
     protected static final boolean ENABLE_HEADS_UP = true;
     // scores above this threshold should be displayed in heads up mode.
@@ -129,8 +130,9 @@
     protected NotificationData mNotificationData = new NotificationData();
     protected NotificationStackScrollLayout mStackScroller;
 
-    protected NotificationData.Entry mInterruptingNotificationEntry;
-    protected long mInterruptingNotificationTime;
+    // for heads up notifications
+    protected HeadsUpNotificationView mHeadsUpNotificationView;
+    protected int mHeadsUpNotificationDecay;
 
     // used to notify status bar for suppressing notification LED
     protected boolean mPanelSlightlyVisible;
@@ -291,7 +293,7 @@
         public void onListenerConnected() {
             if (DEBUG) Log.d(TAG, "onListenerConnected");
             final StatusBarNotification[] notifications = getActiveNotifications();
-            final Ranking currentRanking = getCurrentRanking();
+            final RankingMap currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -303,41 +305,41 @@
         }
 
         @Override
-        public void onNotificationPosted(final StatusBarNotification sbn) {
+        public void onNotificationPosted(final StatusBarNotification sbn,
+                final RankingMap rankingMap) {
             if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
-            final Ranking currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (mNotificationData.findByKey(sbn.getKey()) != null) {
-                        updateNotificationInternal(sbn, currentRanking);
+                    if (mNotificationData.findByKey(sbn.getKey()) != null ||
+                            isHeadsUp(sbn.getKey())) {
+                        updateNotificationInternal(sbn, rankingMap);
                     } else {
-                        addNotificationInternal(sbn, currentRanking);
+                        addNotificationInternal(sbn, rankingMap);
                     }
                 }
             });
         }
 
         @Override
-        public void onNotificationRemoved(final StatusBarNotification sbn) {
+        public void onNotificationRemoved(final StatusBarNotification sbn,
+                final RankingMap rankingMap) {
             if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
-            final Ranking currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    removeNotificationInternal(sbn.getKey(), currentRanking);
+                    removeNotificationInternal(sbn.getKey(), rankingMap);
                 }
             });
         }
 
         @Override
-        public void onNotificationRankingUpdate() {
+        public void onNotificationRankingUpdate(final RankingMap rankingMap) {
             if (DEBUG) Log.d(TAG, "onRankingUpdate");
-            final Ranking currentRanking = getCurrentRanking();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    updateRankingInternal(currentRanking);
+                    updateRankingInternal(rankingMap);
                 }
             });
         }
@@ -384,6 +386,7 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
         mRecents = getComponent(RecentsComponent.class);
+        mRecents.setCallback(this);
 
         mLocale = mContext.getResources().getConfiguration().locale;
         mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
@@ -466,6 +469,10 @@
         // should be overridden
     }
 
+    public boolean isHeadsUp(String key) {
+      return mHeadsUpNotificationView != null && mHeadsUpNotificationView.isShowing(key);
+    }
+
     public boolean notificationIsForCurrentProfiles(StatusBarNotification n) {
         final int thisUserId = mCurrentUserId;
         final int notificationUserId = n.getUserId();
@@ -505,8 +512,8 @@
 
     protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
         View vetoButton = row.findViewById(R.id.veto);
-        if (n.isClearable() || (mInterruptingNotificationEntry != null
-                && mInterruptingNotificationEntry.row == row)) {
+        if (n.isClearable() || (mHeadsUpNotificationView.getEntry() != null
+                && mHeadsUpNotificationView.getEntry().row == row)) {
             final String _pkg = n.getPackageName();
             final String _tag = n.getTag();
             final int _id = n.getId();
@@ -763,8 +770,19 @@
         }
     }
 
+    @Override
+    public void onVisibilityChanged(boolean visible) {
+        // Do nothing
+    }
+
     public abstract void resetHeadsUpDecayTimer();
 
+    public abstract void scheduleHeadsUpOpen();
+
+    public abstract void scheduleHeadsUpClose();
+
+    public abstract void scheduleHeadsUpEscalation();
+
     /**
      * Save the current "public" (locked and secure) state of the lockscreen.
      */
@@ -796,6 +814,18 @@
         return mUsersAllowingPrivateNotifications.get(userHandle);
     }
 
+    public void onNotificationClear(StatusBarNotification notification) {
+        try {
+            mBarService.onNotificationClear(
+                    notification.getPackageName(),
+                    notification.getTag(),
+                    notification.getId(),
+                    notification.getUserId());
+        } catch (android.os.RemoteException ex) {
+            // oh well
+        }
+    }
+
     protected class H extends Handler {
         public void handleMessage(Message m) {
             Intent intent;
@@ -873,10 +903,7 @@
     }
 
     public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
-        int minHeight =
-                mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
-        int maxHeight =
-                mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+        int maxHeight = mRowMaxHeight;
         StatusBarNotification sbn = entry.notification;
         RemoteViews contentView = sbn.getNotification().contentView;
         RemoteViews bigContentView = sbn.getNotification().bigContentView;
@@ -1039,7 +1066,7 @@
             }
         }
         entry.row = row;
-        entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
+        entry.row.setHeightRange(mRowMinHeight, maxHeight);
         entry.row.setOnActivatedListener(this);
         entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
         entry.expanded = contentViewLocal;
@@ -1101,7 +1128,7 @@
 
                     try {
                         if (mIsHeadsUp) {
-                            mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+                            mHeadsUpNotificationView.clear();
                         }
                         mBarService.onNotificationClick(mNotificationKey);
                     } catch (RemoteException ex) {
@@ -1157,7 +1184,7 @@
         }
     }
 
-    protected StatusBarNotification removeNotificationViews(String key, Ranking ranking) {
+    protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
         NotificationData.Entry entry = mNotificationData.remove(key, ranking);
         if (entry == null) {
             Log.w(TAG, "removeNotification for unknown key: " + key);
@@ -1197,7 +1224,7 @@
         return entry;
     }
 
-    protected void addNotificationViews(Entry entry, Ranking ranking) {
+    protected void addNotificationViews(Entry entry, RankingMap ranking) {
         if (entry == null) {
             return;
         }
@@ -1206,7 +1233,7 @@
         updateNotifications();
     }
 
-    private void addNotificationViews(StatusBarNotification notification, Ranking ranking) {
+    private void addNotificationViews(StatusBarNotification notification, RankingMap ranking) {
         addNotificationViews(createNotificationViews(notification), ranking);
     }
 
@@ -1292,9 +1319,9 @@
     }
 
     public abstract void addNotificationInternal(StatusBarNotification notification,
-            Ranking ranking);
+            RankingMap ranking);
 
-    protected abstract void updateRankingInternal(Ranking ranking);
+    protected abstract void updateRankingInternal(RankingMap ranking);
 
     @Override
     public void removeNotification(String key) {
@@ -1303,7 +1330,7 @@
         }
     }
 
-    public abstract void removeNotificationInternal(String key, Ranking ranking);
+    public abstract void removeNotificationInternal(String key, RankingMap ranking);
 
     public void updateNotification(StatusBarNotification notification) {
         if (!USE_NOTIFICATION_LISTENER) {
@@ -1311,12 +1338,18 @@
         }
     }
 
-    public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+    public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
 
-        final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
+        final String key = notification.getKey();
+        boolean wasHeadsUp = isHeadsUp(key);
+        NotificationData.Entry oldEntry;
+        if (wasHeadsUp) {
+            oldEntry = mHeadsUpNotificationView.getEntry();
+        } else {
+            oldEntry = mNotificationData.findByKey(key);
+        }
         if (oldEntry == null) {
-            Log.w(TAG, "updateNotification for unknown key: " + notification.getKey());
             return;
         }
 
@@ -1382,61 +1415,99 @@
                         && oldPublicContentView.getPackage() != null
                         && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
                         && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
-
-
         boolean updateTicker = notification.getNotification().tickerText != null
                 && !TextUtils.equals(notification.getNotification().tickerText,
                 oldEntry.notification.getNotification().tickerText);
+
+        final boolean shouldInterrupt = shouldInterrupt(notification);
+        final boolean alertAgain = alertAgain(oldEntry);
+        boolean updateSuccessful = false;
         if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
                 && publicUnchanged) {
-            if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey());
+            if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
             oldEntry.notification = notification;
             try {
-                updateNotificationViews(oldEntry, notification);
-
-                if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
-                        && oldNotification == mInterruptingNotificationEntry.notification) {
-                    if (!shouldInterrupt(notification)) {
-                        if (DEBUG) Log.d(TAG, "no longer interrupts!");
-                        mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
-                    } else {
-                        if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
-                        mInterruptingNotificationEntry.notification = notification;
-                        updateHeadsUpViews(mInterruptingNotificationEntry, notification);
+                if (oldEntry.icon != null) {
+                    // Update the icon
+                    final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
+                            notification.getUser(),
+                            notification.getNotification().icon,
+                            notification.getNotification().iconLevel,
+                            notification.getNotification().number,
+                            notification.getNotification().tickerText);
+                    if (!oldEntry.icon.set(ic)) {
+                        handleNotificationError(notification, "Couldn't update icon: " + ic);
+                        return;
                     }
                 }
 
-                // Update the icon.
-                final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
-                        notification.getUser(),
-                        notification.getNotification().icon, notification.getNotification().iconLevel,
-                        notification.getNotification().number,
-                        notification.getNotification().tickerText);
-                if (!oldEntry.icon.set(ic)) {
-                    handleNotificationError(notification, "Couldn't update icon: " + ic);
-                    return;
+                if (wasHeadsUp) {
+                    if (shouldInterrupt) {
+                        updateHeadsUpViews(oldEntry, notification);
+                        if (alertAgain) {
+                            resetHeadsUpDecayTimer();
+                        }
+                    } else {
+                        // we updated the notification above, so release to build a new shade entry
+                        mHeadsUpNotificationView.releaseAndClose();
+                        return;
+                    }
+                } else {
+                    if (shouldInterrupt && alertAgain) {
+                        removeNotificationViews(key, ranking);
+                        addNotificationInternal(notification, ranking);  //this will pop the headsup
+                    } else {
+                        updateNotificationViews(oldEntry, notification);
+                    }
                 }
                 mNotificationData.updateRanking(ranking);
                 updateNotifications();
+                updateSuccessful = true;
             }
             catch (RuntimeException e) {
                 // It failed to add cleanly.  Log, and remove the view from the panel.
                 Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
-                removeNotificationViews(notification.getKey(), ranking);
-                addNotificationViews(notification, ranking);
             }
-        } else {
-            if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey());
-            if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
-            removeNotificationViews(notification.getKey(), ranking);
-            addNotificationViews(notification, ranking);  // will also replace the heads up
-            final NotificationData.Entry newEntry = mNotificationData.findByKey(
-                    notification.getKey());
-            final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
-            if (userChangedExpansion) {
-                boolean userExpanded = oldEntry.row.isUserExpanded();
-                newEntry.row.setUserExpanded(userExpanded);
-                newEntry.row.notifyHeightChanged();
+        }
+        if (!updateSuccessful) {
+            if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
+            if (wasHeadsUp) {
+                if (shouldInterrupt) {
+                    if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
+                    Entry newEntry = new Entry(notification, null);
+                    ViewGroup holder = mHeadsUpNotificationView.getHolder();
+                    if (inflateViewsForHeadsUp(newEntry, holder)) {
+                        mHeadsUpNotificationView.showNotification(newEntry);
+                        if (alertAgain) {
+                            resetHeadsUpDecayTimer();
+                        }
+                    } else {
+                        Log.w(TAG, "Couldn't create new updated headsup for package "
+                                + contentView.getPackage());
+                    }
+                } else {
+                    if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
+                    oldEntry.notification = notification;
+                    mHeadsUpNotificationView.releaseAndClose();
+                    return;
+                }
+            } else {
+                if (shouldInterrupt && alertAgain) {
+                    if (DEBUG) Log.d(TAG, "reposting to invoke heads up for key: " + key);
+                    removeNotificationViews(key, ranking);
+                    addNotificationInternal(notification, ranking);  //this will pop the headsup
+                } else {
+                    if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key);
+                    removeNotificationViews(key, ranking);
+                    addNotificationViews(notification, ranking);
+                    final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
+                    final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
+                    if (userChangedExpansion) {
+                        boolean userExpanded = oldEntry.row.isUserExpanded();
+                        newEntry.row.setUserExpanded(userExpanded);
+                        newEntry.row.notifyHeightChanged();
+                    }
+                }
             }
         }
 
@@ -1511,11 +1582,17 @@
     }
 
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
-        if (!screenOn && mInterruptingNotificationEntry != null) {
-            mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+        if (!screenOn) {
+            scheduleHeadsUpEscalation();
         }
     }
 
+    private boolean alertAgain(Entry entry) {
+        final StatusBarNotification sbn = entry.notification;
+        return entry == null || !entry.hasInterrupted()
+                || (sbn.getNotification().flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
+    }
+
     protected boolean shouldInterrupt(StatusBarNotification sbn) {
         Notification notification = sbn.getNotification();
         // some predicates to make the boolean logic legible
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 4233ab8..bfa74fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -21,6 +21,7 @@
 import android.os.Process;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -58,17 +59,18 @@
         updateSyntheticNotification();
     }
 
-    public boolean tryIntercept(StatusBarNotification notification, Ranking ranking) {
-        if (ranking == null) return false;
+    public boolean tryIntercept(StatusBarNotification notification, RankingMap rankingMap) {
+        if (rankingMap == null) return false;
         if (shouldDisplayIntercepted()) return false;
         if (mReleased.contains(notification.getKey())) return false;
-        if (!ranking.isInterceptedByDoNotDisturb(notification.getKey())) return false;
+        Ranking ranking = rankingMap.getRanking(notification.getKey());
+        if (!ranking.isInterceptedByDoNotDisturb()) return false;
         mIntercepted.put(notification.getKey(), notification);
         updateSyntheticNotification();
         return true;
     }
 
-    public void retryIntercepts(Ranking ranking) {
+    public void retryIntercepts(RankingMap ranking) {
         if (ranking == null) return;
 
         final int N = mIntercepted.size();
@@ -111,7 +113,7 @@
             return;
         }
         final Notification n = new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_qs_zen_on)
+                .setSmallIcon(R.drawable.ic_notify_zen)
                 .setContentTitle(mContext.getResources().getQuantityString(
                         R.plurals.zen_mode_notification_title,
                         mIntercepted.size(), mIntercepted.size()))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 631e19c..9921c55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -18,6 +18,7 @@
 
 import android.app.Notification;
 import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 
@@ -67,15 +68,23 @@
         public void setInterruption() {
             interruption = true;
         }
+
+        public boolean hasInterrupted() {
+            return interruption;
+        }
     }
 
     private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
-    private Ranking mRanking;
+    private RankingMap mRanking;
     private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
         @Override
         public int compare(Entry a, Entry b) {
             if (mRanking != null) {
-                return mRanking.getRank(a.key) - mRanking.getRank(b.key);
+                Ranking aRanking = mRanking.getRanking(a.key);
+                Ranking bRanking = mRanking.getRanking(b.key);
+                int aRank = aRanking != null ? aRanking.getRank() : -1;
+                int bRank = bRanking != null ? bRanking.getRank() : -1;
+                return aRank - bRank;
             }
 
             final StatusBarNotification na = a.notification;
@@ -108,12 +117,12 @@
         return null;
     }
 
-    public void add(Entry entry, Ranking ranking) {
+    public void add(Entry entry, RankingMap ranking) {
         mEntries.add(entry);
         updateRankingAndSort(ranking);
     }
 
-    public Entry remove(String key, Ranking ranking) {
+    public Entry remove(String key, RankingMap ranking) {
         Entry e = findByKey(key);
         if (e == null) {
             return null;
@@ -123,7 +132,7 @@
         return e;
     }
 
-    public void updateRanking(Ranking ranking) {
+    public void updateRanking(RankingMap ranking) {
         updateRankingAndSort(ranking);
     }
 
@@ -137,12 +146,13 @@
                 }
             }
         } else {
-            return mRanking.isAmbient(key);
+            Ranking ranking = mRanking.getRanking(key);
+            return ranking != null && ranking.isAmbient();
         }
         return false;
     }
 
-    private void updateRankingAndSort(Ranking ranking) {
+    private void updateRankingAndSort(RankingMap ranking) {
         if (ranking != null) {
             mRanking = ranking;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
deleted file mode 100644
index 1503072..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
+++ /dev/null
@@ -1,52 +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.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotView extends View {
-
-    private final Paint mPaint = new Paint();
-
-    public SpeedBumpDotView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mPaint.setAntiAlias(true);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        float radius = getWidth() / 2.0f;
-        canvas.drawCircle(radius, radius, radius, mPaint);
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    public void setColor(int color) {
-        mPaint.setColor(color);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
deleted file mode 100644
index cac6327..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
+++ /dev/null
@@ -1,80 +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 com.android.systemui.R;
-
-/**
- * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
- * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
- */
-public class SpeedBumpDotsAlgorithm {
-
-    private final float mDotRadius;
-
-    public SpeedBumpDotsAlgorithm(Context context) {
-        mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
-                / 2.0f;
-    }
-
-    public void getState(SpeedBumpDotsState resultState) {
-
-        // First reset the current state and ensure that every View has a ViewState
-        resultState.resetViewStates();
-
-        SpeedBumpDotsLayout hostView = resultState.getHostView();
-        boolean currentlyVisible = hostView.isCurrentlyVisible();
-        resultState.setActiveState(currentlyVisible
-                ? SpeedBumpDotsState.SHOWN
-                : SpeedBumpDotsState.HIDDEN);
-        int hostWidth = hostView.getWidth();
-        float layoutWidth = hostWidth - 2 * mDotRadius;
-        int childCount = hostView.getChildCount();
-        float paddingBetween = layoutWidth / (childCount - 1);
-        float centerY = hostView.getHeight() / 2.0f;
-        for (int i = 0; i < childCount; i++) {
-            View child = hostView.getChildAt(i);
-            SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
-            if (currentlyVisible) {
-                float xTranslation = i * paddingBetween;
-                viewState.xTranslation = xTranslation;
-                viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
-                        layoutWidth);
-            } else {
-                viewState.xTranslation = layoutWidth / 2;
-                viewState.yTranslation = centerY - mDotRadius;
-            }
-            viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
-            viewState.scale = currentlyVisible ? 1.0f : 0.5f;
-        }
-    }
-
-    private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
-            float xTranslation, float layoutWidth) {
-        float t = hostView.getAnimationProgress();
-        if (t == 0.0f || t == 1.0f) {
-            return centerY - mDotRadius;
-        }
-        float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
-        float partialOffset = xTranslation / layoutWidth;
-        float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
-        return (1.0f - indentFactor) * centerY - mDotRadius;
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
deleted file mode 100644
index ddf5215..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
+++ /dev/null
@@ -1,136 +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.animation.TimeAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import com.android.systemui.R;
-
-/**
- * A layout with a certain number of dots which are integrated in the
- * {@link com.android.systemui.statusbar.SpeedBumpView}
- */
-public class SpeedBumpDotsLayout extends ViewGroup {
-
-    private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
-    private final int mDotSize;
-    private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
-    private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
-    private boolean mIsCurrentlyVisible = true;
-    private final ValueAnimator mClickAnimator;
-    private float mAnimationProgress;
-    private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
-            = new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            mAnimationProgress = animation.getAnimatedFraction();
-            updateChildren();
-        }
-    };
-
-    public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
-        createDots(context, attrs);
-        mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
-        mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
-        mClickAnimator.addUpdateListener(mClickUpdateListener);
-    }
-
-    private void createDots(Context context, AttributeSet attrs) {
-        SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
-        blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
-        addView(blueDot);
-
-        SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
-        redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
-        addView(redDot);
-
-        SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
-        yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
-        addView(yellowDot);
-
-        SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
-        greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
-        addView(greenDot);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
-                MeasureSpec.getMode(widthMeasureSpec));
-        int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
-                MeasureSpec.getMode(heightMeasureSpec));
-        measureChildren(childWidthSpec, childHeightSpec);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            child.layout(0, 0, mDotSize, mDotSize);
-        }
-        if (changed) {
-            updateChildren();
-        }
-    }
-
-    private void updateChildren() {
-        mAlgorithm.getState(mCurrentState);
-        mCurrentState.apply();
-    }
-
-    public void performVisibilityAnimation(boolean visible) {
-        if (mClickAnimator.isRunning()) {
-            mClickAnimator.cancel();
-        }
-        mIsCurrentlyVisible = visible;
-        mAlgorithm.getState(mCurrentState);
-        mCurrentState.animateToState();
-    }
-
-    public void setInvisible() {
-        mIsCurrentlyVisible = false;
-        mAlgorithm.getState(mCurrentState);
-        mCurrentState.apply();
-    }
-
-    public boolean isCurrentlyVisible() {
-        return mIsCurrentlyVisible;
-    }
-
-    public void performDotClickAnimation() {
-        if (mClickAnimator.isRunning()) {
-            // don't perform an animation if it's running already
-            return;
-        }
-        mClickAnimator.start();
-    }
-
-
-    public float getAnimationProgress() {
-        return mAnimationProgress;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
deleted file mode 100644
index 4febab1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
+++ /dev/null
@@ -1,128 +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.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotsState {
-
-    public static final int HIDDEN = 1;
-    public static final int SHOWN = 2;
-    private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
-
-    private final SpeedBumpDotsLayout mHostView;
-    private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
-    private final Interpolator mFastOutSlowInInterpolator;
-    private int mActiveState = 0;
-
-    public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
-        mHostView = hostLayout;
-        mFastOutSlowInInterpolator = AnimationUtils
-                .loadInterpolator(hostLayout.getContext(),
-                        android.R.interpolator.fast_out_slow_in);
-    }
-
-    public SpeedBumpDotsLayout getHostView() {
-        return mHostView;
-    }
-
-    public void resetViewStates() {
-        int numChildren = mHostView.getChildCount();
-        for (int i = 0; i < numChildren; i++) {
-            View child = mHostView.getChildAt(i);
-            ViewState viewState = mStateMap.get(child);
-            if (viewState == null) {
-                viewState = new ViewState();
-                mStateMap.put(child, viewState);
-            }
-        }
-    }
-
-    public ViewState getViewStateForView(View requestedView) {
-        return mStateMap.get(requestedView);
-    }
-
-    public void apply() {
-        int childCount = mHostView.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = mHostView.getChildAt(i);
-            ViewState viewState = mStateMap.get(child);
-
-            child.setTranslationX(viewState.xTranslation);
-            child.setTranslationY(viewState.yTranslation);
-            child.setScaleX(viewState.scale);
-            child.setScaleY(viewState.scale);
-            child.setAlpha(viewState.alpha);
-        }
-    }
-
-    public void animateToState() {
-        int childCount = mHostView.getChildCount();
-        int middleIndex = (childCount - 1) / 2;
-        long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
-        boolean isAppearing = getActiveState() == SHOWN;
-        boolean isDisappearing = getActiveState() == HIDDEN;
-        for (int i = 0; i < childCount; i++) {
-            int delayIndex;
-            if (i <= middleIndex) {
-                delayIndex = i * 2;
-            } else {
-                int distToMiddle = i - middleIndex;
-                delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
-            }
-            long startDelay = 0;
-            if (isAppearing || isDisappearing) {
-                if (isDisappearing) {
-                    delayIndex = childCount - 1 - delayIndex;
-                }
-                startDelay = delayIndex * delayPerElement;
-            }
-            View child = mHostView.getChildAt(i);
-            ViewState viewState = mStateMap.get(child);
-            child.animate().setInterpolator(mFastOutSlowInInterpolator)
-                    .setStartDelay(startDelay)
-                    .alpha(viewState.alpha)
-                    .translationX(viewState.xTranslation)
-                    .translationY(viewState.yTranslation)
-                    .scaleX(viewState.scale).scaleY(viewState.scale);
-        }
-    }
-
-    public int getActiveState() {
-        return mActiveState;
-    }
-
-    public void setActiveState(int mActiveState) {
-        this.mActiveState = mActiveState;
-    }
-
-    public static class ViewState {
-        float xTranslation;
-        float yTranslation;
-        float alpha;
-        float scale;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index 689d0e9..f80f0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -16,71 +16,26 @@
 
 package com.android.systemui.statusbar;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Outline;
 import android.util.AttributeSet;
-import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.widget.TextView;
 import com.android.systemui.R;
 
 /**
  * The view representing the separation between important and less important notifications
  */
-public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+public class SpeedBumpView extends ExpandableView {
 
-    private final int mCollapsedHeight;
-    private final int mDotsHeight;
-    private final int mTextPaddingInset;
-    private SpeedBumpDotsLayout mDots;
-    private AlphaOptimizedView mLineLeft;
-    private AlphaOptimizedView mLineRight;
-    private boolean mIsExpanded;
-    private boolean mDividerVisible = true;
-    private ValueAnimator mCurrentAnimator;
+    private final int mSpeedBumpHeight;
+    private AlphaOptimizedView mLine;
+    private boolean mIsVisible = true;
     private final Interpolator mFastOutSlowInInterpolator;
-    private float mCenterX;
-    private TextView mExplanationText;
-    private boolean mExplanationTextVisible = false;
-    private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
-        private boolean mCancelled;
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            if (!mCancelled) {
-                mExplanationText.setVisibility(View.INVISIBLE);
-            }
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            mCancelled = true;
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-            mCancelled = false;
-        }
-    };
-    private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mCurrentAnimator = null;
-        }
-    };
 
     public SpeedBumpView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mCollapsedHeight = getResources()
-                .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
-        mTextPaddingInset = getResources().getDimensionPixelSize(
-                R.dimen.speed_bump_text_padding_inset);
-        mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
-        setOnClickListener(this);
+        mSpeedBumpHeight = getResources()
+                .getDimensionPixelSize(R.dimen.speed_bump_height);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
     }
@@ -88,111 +43,41 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
-        mLineLeft = (AlphaOptimizedView) findViewById(R.id.speedbump_line_left);
-        mLineRight = (AlphaOptimizedView) findViewById(R.id.speedbump_line_right);
-        mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
-        resetExplanationText();
-
+        mLine = (AlphaOptimizedView) findViewById(R.id.speedbump_line);
     }
 
     @Override
     protected int getInitialHeight() {
-        return mCollapsedHeight;
+        return mSpeedBumpHeight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        if (mCurrentAnimator != null) {
-            // expand animation is running
-            return getActualHeight();
-        }
-        return mIsExpanded ? getHeight() : mCollapsedHeight;
+        return mSpeedBumpHeight;
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        Outline outline = new Outline();
-        mCenterX = getWidth() / 2;
-        float centerY = getHeight() / 2;
-        // TODO: hide outline better
-        // Temporary workaround to hide outline on a transparent view
-        int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
-        int outlineTop = (int) (centerY - mDotsHeight / 2);
-        outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
-                outlineTop + mDotsHeight);
-        setOutline(outline);
-        mLineLeft.setPivotX(mLineLeft.getWidth());
-        mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
-        mLineRight.setPivotX(0);
-        mLineRight.setPivotY(mLineRight.getHeight() / 2);
+        mLine.setPivotX(mLine.getWidth() / 2);
+        mLine.setPivotY(mLine.getHeight() / 2);
+        setOutline(null);
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         measureChildren(widthMeasureSpec, heightMeasureSpec);
-        int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+        int height = mSpeedBumpHeight;
         setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
     }
 
     @Override
-    public void onClick(View v) {
-        if (mCurrentAnimator != null) {
-            return;
-        }
-        int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
-        int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
-        mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
-        mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
-        mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                setActualHeight((int) animation.getAnimatedValue());
-            }
-        });
-        mCurrentAnimator.addListener(mAnimationFinishedListener);
-        mCurrentAnimator.start();
-        mIsExpanded = !mIsExpanded;
-        mDots.performDotClickAnimation();
-        animateExplanationTextInternal(mIsExpanded);
-    }
-
-    private void animateExplanationTextInternal(boolean visible) {
-        if (mExplanationTextVisible != visible) {
-            float translationY = 0.0f;
-            float scale = 0.5f;
-            float alpha = 0.0f;
-            boolean needsHideListener = true;
-            if (visible) {
-                mExplanationText.setVisibility(VISIBLE);
-                translationY = mDots.getBottom() - mTextPaddingInset;
-                scale = 1.0f;
-                alpha = 1.0f;
-                needsHideListener = false;
-            }
-            mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
-                    .alpha(alpha)
-                    .scaleX(scale)
-                    .scaleY(scale)
-                    .translationY(translationY)
-                    .setListener(needsHideListener ? mHideExplanationListener : null);
-            mExplanationTextVisible = visible;
-        }
-    }
-
-    @Override
     public boolean isTransparent() {
         return true;
     }
 
     public void performVisibilityAnimation(boolean nowVisible) {
         animateDivider(nowVisible, null /* onFinishedRunnable */);
-
-        // Animate explanation Text
-        if (mIsExpanded) {
-            animateExplanationTextInternal(nowVisible);
-        }
     }
 
     /**
@@ -203,28 +88,16 @@
      *        finished.
      */
     public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) {
-        if (nowVisible != mDividerVisible) {
+        if (nowVisible != mIsVisible) {
             // Animate dividers
             float endValue = nowVisible ? 1.0f : 0.0f;
-            float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
-            float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
-            mLineLeft.animate()
+            mLine.animate()
                     .alpha(endValue)
                     .scaleX(endValue)
                     .scaleY(endValue)
-                    .translationX(endTranslationXLeft)
                     .setInterpolator(mFastOutSlowInInterpolator)
                     .withEndAction(onFinishedRunnable);
-            mLineRight.animate()
-                    .alpha(endValue)
-                    .scaleX(endValue)
-                    .scaleY(endValue)
-                    .translationX(endTranslationXRight)
-                    .setInterpolator(mFastOutSlowInInterpolator);
-
-            // Animate dots
-            mDots.performVisibilityAnimation(nowVisible);
-            mDividerVisible = nowVisible;
+            mIsVisible = nowVisible;
         } else {
             if (onFinishedRunnable != null) {
                 onFinishedRunnable.run();
@@ -233,34 +106,10 @@
     }
 
     public void setInvisible() {
-        float endTranslationXLeft = mCenterX - mLineLeft.getRight();
-        float endTranslationXRight = mCenterX - mLineRight.getLeft();
-        mLineLeft.setAlpha(0.0f);
-        mLineLeft.setScaleX(0.0f);
-        mLineLeft.setScaleY(0.0f);
-        mLineLeft.setTranslationX(endTranslationXLeft);
-        mLineRight.setAlpha(0.0f);
-        mLineRight.setScaleX(0.0f);
-        mLineRight.setScaleY(0.0f);
-        mLineRight.setTranslationX(endTranslationXRight);
-        mDots.setInvisible();
-        resetExplanationText();
-
-        mDividerVisible = false;
-    }
-
-    public void collapse() {
-        if (mIsExpanded) {
-            setActualHeight(mCollapsedHeight);
-            mIsExpanded = false;
-        }
-        resetExplanationText();
-    }
-
-    public void animateExplanationText(boolean nowVisible) {
-        if (mIsExpanded) {
-            animateExplanationTextInternal(nowVisible);
-        }
+        mLine.setAlpha(0.0f);
+        mLine.setScaleX(0.0f);
+        mLine.setScaleY(0.0f);
+        mIsVisible = false;
     }
 
     @Override
@@ -272,17 +121,4 @@
     public void performAddAnimation(long delay) {
         performVisibilityAnimation(true);
     }
-
-    private void resetExplanationText() {
-        mExplanationText.setTranslationY(0);
-        mExplanationText.setVisibility(INVISIBLE);
-        mExplanationText.setAlpha(0.0f);
-        mExplanationText.setScaleX(0.5f);
-        mExplanationText.setScaleY(0.5f);
-        mExplanationTextVisible = false;
-    }
-
-    public boolean isExpanded() {
-        return mIsExpanded;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
index 086a266..e312d58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
@@ -423,6 +423,7 @@
             return;
         }
         if (!animate) {
+            view.animate().cancel();
             view.setAlpha(alpha);
             view.setScaleX(scale);
             view.setScaleY(scale);
@@ -465,6 +466,13 @@
     }
 
     public void reset() {
+        if (mSwipeAnimator != null) {
+            mSwipeAnimator.cancel();
+        }
+        ArrayList<View> targetViews = mCallback.getTranslationViews();
+        for (View view : targetViews) {
+            view.animate().cancel();
+        }
         setTranslation(0.0f, true);
         mSwipingInProgress = false;
     }
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 34179cb..dde95bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -688,6 +688,9 @@
 
     @Override
     protected boolean isScrolledToBottom() {
+        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
+            return true;
+        }
         if (!isInSettings()) {
             return mNotificationStackScroller.isScrolledToBottom();
         }
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 772d0e7..1f3098d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
@@ -67,6 +68,11 @@
     private VelocityTrackerInterface mVelocityTracker;
     private FlingAnimationUtils mFlingAnimationUtils;
 
+    /**
+     * Whether an instant expand request is currently pending and we are just waiting for layout.
+     */
+    private boolean mInstantExpanding;
+
     PanelBar mBar;
 
     protected int mMaxPanelHeight = -1;
@@ -128,6 +134,9 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
+        if (mInstantExpanding) {
+            return false;
+        }
 
         /*
          * We capture touch events here and update the expand height here in case according to
@@ -263,6 +272,9 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (mInstantExpanding) {
+            return false;
+        }
 
         /*
          * If the user drags anywhere inside the panel we intercept it if he moves his finger
@@ -556,6 +568,41 @@
         }
     }
 
+    public void instantExpand() {
+        mInstantExpanding = true;
+        abortAnimations();
+        if (mTracking) {
+            onTrackingStopped(true /* expands */); // The panel is expanded after this call.
+            onExpandingFinished();
+        }
+        setVisibility(VISIBLE);
+
+        // Wait for window manager to pickup the change, so we know the maximum height of the panel
+        // then.
+        getViewTreeObserver().addOnGlobalLayoutListener(
+                new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        if (mStatusBar.getStatusBarWindow().getHeight()
+                                != mStatusBar.getStatusBarHeight()) {
+                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                            setExpandedFraction(1f);
+                            mInstantExpanding = false;
+                        }
+                    }
+                });
+
+        // Make sure a layout really happens.
+        requestLayout();
+    }
+
+    private void abortAnimations() {
+        cancelPeek();
+        if (mHeightAnimator != null) {
+            mHeightAnimator.cancel();
+        }
+    }
+
     protected void startUnlockHintAnimation() {
 
         // We don't need to hint the user if an animation is already running or the user is changing
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 a8f61f3..1da7dab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -64,7 +64,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
@@ -103,6 +103,7 @@
 import com.android.systemui.qs.CircularClipper;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
@@ -277,10 +278,6 @@
     // the date view
     DateView mDateView;
 
-    // for heads up notifications
-    private HeadsUpNotificationView mHeadsUpNotificationView;
-    private int mHeadsUpNotificationDecay;
-
     // on-screen navigation buttons
     private NavigationBarView mNavigationBarView = null;
     private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -366,7 +363,7 @@
                 if (!mUseHeadsUp) {
                     Log.d(TAG, "dismissing any existing heads up notification on disable event");
                     setHeadsUpVisibility(false);
-                    mHeadsUpNotificationView.setNotification(null);
+                    mHeadsUpNotificationView.release();
                     removeHeadsUpView();
                 } else {
                     addHeadsUpView();
@@ -818,6 +815,10 @@
         return mStatusBarView;
     }
 
+    public StatusBarWindowView getStatusBarWindow() {
+        return mStatusBarWindow;
+    }
+
     @Override
     protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
         boolean opaque = false;
@@ -1050,7 +1051,7 @@
     }
 
     @Override
-    public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+    public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
         if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
         if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification, ranking)) {
             // Forward the ranking so we can sort the new notification.
@@ -1061,31 +1062,26 @@
         displayNotification(notification, ranking);
     }
 
-    public void displayNotification(StatusBarNotification notification,
-            Ranking ranking) {
-        Entry shadeEntry = createNotificationViews(notification);
-        if (shadeEntry == null) {
-            return;
-        }
+    public void displayNotification(StatusBarNotification notification, RankingMap ranking) {
         if (mUseHeadsUp && shouldInterrupt(notification)) {
             if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
             Entry interruptionCandidate = new Entry(notification, null);
             ViewGroup holder = mHeadsUpNotificationView.getHolder();
             if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
-                mInterruptingNotificationTime = System.currentTimeMillis();
-                mInterruptingNotificationEntry = interruptionCandidate;
-                shadeEntry.setInterruption();
-
                 // 1. Populate mHeadsUpNotificationView
-                mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
+                mHeadsUpNotificationView.showNotification(interruptionCandidate);
 
-                // 2. Animate mHeadsUpNotificationView in
-                mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
-
-                // 3. Set alarm to age the notification off
-                resetHeadsUpDecayTimer();
+                // do not show the notification in the shade, yet.
+                return;
             }
-        } else if (notification.getNotification().fullScreenIntent != null) {
+        }
+
+        Entry shadeEntry = createNotificationViews(notification);
+        if (shadeEntry == null) {
+            return;
+        }
+
+        if (notification.getNotification().fullScreenIntent != null) {
             // Stop screensaver if the notification has a full-screen intent.
             // (like an incoming phone call)
             awakenDreams();
@@ -1100,7 +1096,7 @@
             // usual case: status bar visible & not immersive
 
             // show the ticker if there isn't already a heads up
-            if (mInterruptingNotificationEntry == null) {
+            if (mHeadsUpNotificationView.getEntry() == null) {
                 tick(notification, true);
             }
         }
@@ -1110,31 +1106,64 @@
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
     }
 
+    public void displayNotificationFromHeadsUp(StatusBarNotification notification) {
+        NotificationData.Entry shadeEntry = createNotificationViews(notification);
+        if (shadeEntry == null) {
+            return;
+        }
+        shadeEntry.setInterruption();
+
+        addNotificationViews(shadeEntry, null);
+        // Recalculate the position of the sliding windows and the titles.
+        setAreThereNotifications();
+        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+    }
+
     @Override
     public void resetHeadsUpDecayTimer() {
-        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        mHandler.removeMessages(MSG_DECAY_HEADS_UP);
         if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
                 && mHeadsUpNotificationView.isClearable()) {
-            mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
+            mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay);
         }
     }
 
     @Override
-    public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+    public void scheduleHeadsUpOpen() {
+        mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+    }
+
+    @Override
+    public void scheduleHeadsUpClose() {
+        mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+    }
+
+    @Override
+    public void scheduleHeadsUpEscalation() {
+        mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+    }
+
+    @Override
+    public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
         super.updateNotificationInternal(notification, ranking);
         // if we're here, then the notification is already in the shade
         mIntercepted.remove(notification.getKey());
     }
 
     @Override
-    protected void updateRankingInternal(Ranking ranking) {
+    protected void updateRankingInternal(RankingMap ranking) {
         mNotificationData.updateRanking(ranking);
         mIntercepted.retryIntercepts(ranking);
         updateNotifications();
     }
 
     @Override
-    public void removeNotificationInternal(String key, Ranking ranking) {
+    public void removeNotificationInternal(String key, RankingMap ranking) {
+        if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
+                && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) {
+            mHeadsUpNotificationView.clear();
+        }
+
         StatusBarNotification old = removeNotificationViews(key, ranking);
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
 
@@ -1147,11 +1176,6 @@
             // Recalculate the position of the sliding windows and the titles.
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
 
-            if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
-                    && old == mInterruptingNotificationEntry.notification) {
-                mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
-            }
-
             if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
                     && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
                 animateCollapsePanels();
@@ -1574,7 +1598,12 @@
                 case MSG_SHOW_HEADS_UP:
                     setHeadsUpVisibility(true);
                     break;
+                case MSG_DECAY_HEADS_UP:
+                    mHeadsUpNotificationView.release();
+                    setHeadsUpVisibility(false);
+                    break;
                 case MSG_HIDE_HEADS_UP:
+                    mHeadsUpNotificationView.release();
                     setHeadsUpVisibility(false);
                     break;
                 case MSG_ESCALATE_HEADS_UP:
@@ -1587,8 +1616,9 @@
 
     /**  if the interrupting notification had a fullscreen intent, fire it now.  */
     private void escalateHeadsUp() {
-        if (mInterruptingNotificationEntry != null) {
-            final StatusBarNotification sbn = mInterruptingNotificationEntry.notification;
+        if (mHeadsUpNotificationView.getEntry() != null) {
+            final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification;
+            mHeadsUpNotificationView.release();
             final Notification notification = sbn.getNotification();
             if (notification.fullScreenIntent != null) {
                 if (DEBUG)
@@ -1676,7 +1706,6 @@
         }
 
         if (mStatusBarWindow != null) {
-
             // release focus immediately to kick off focus change transition
             mStatusBarWindowManager.setStatusBarFocusable(false);
 
@@ -1918,6 +1947,10 @@
                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
                 Integer.toHexString(diff)));
         if (diff != 0) {
+            // we never set the recents bit via this method, so save the prior state to prevent
+            // clobbering the bit below
+            final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
+
             mSystemUiVisibility = newVal;
 
             // update low profile
@@ -1972,6 +2005,11 @@
                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
             }
 
+            // restore the recents bit
+            if (wasRecentsVisible) {
+                mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
+            }
+
             // send updated sysui visibility to window manager
             notifyUiVisibilityChanged(mSystemUiVisibility);
         }
@@ -2243,7 +2281,7 @@
         pw.print("  mUseHeadsUp=");
         pw.println(mUseHeadsUp);
         pw.print("  interrupting package: ");
-        pw.println(hunStateToString(mInterruptingNotificationEntry));
+        pw.println(hunStateToString(mHeadsUpNotificationView.getEntry()));
         dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
         if (mNavigationBarView != null) {
             pw.print("  mNavigationBarWindowState=");
@@ -2494,6 +2532,7 @@
         repositionNavigationBar();
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
         updateShowSearchHoldoff();
+        updateRowStates();
     }
 
     @Override
@@ -2517,26 +2556,10 @@
         if (!ENABLE_HEADS_UP) return;
         if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
         mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
-        if (!vis) {
-            if (DEBUG) Log.d(TAG, "setting heads up entry to null");
-            mInterruptingNotificationEntry = null;
-        }
     }
 
     public void onHeadsUpDismissed() {
-        if (mInterruptingNotificationEntry == null) return;
-        mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
-        if (mHeadsUpNotificationView.isClearable()) {
-            try {
-                mBarService.onNotificationClear(
-                        mInterruptingNotificationEntry.notification.getPackageName(),
-                        mInterruptingNotificationEntry.notification.getTag(),
-                        mInterruptingNotificationEntry.notification.getId(),
-                        mInterruptingNotificationEntry.notification.getUserId());
-            } catch (android.os.RemoteException ex) {
-                // oh well
-            }
-        }
+        mHeadsUpNotificationView.dismiss();
     }
 
     /**
@@ -2905,7 +2928,6 @@
             mNotificationPanel.setKeyguardShowing(false);
             mScrimController.setKeyguardShowing(false);
         }
-
         updateStackScrollerState();
         updatePublicMode();
         updateNotifications();
@@ -2921,6 +2943,11 @@
                 ? View.INVISIBLE : View.VISIBLE);
         mStackScroller.setScrollingEnabled(!onKeyguard);
         mStackScroller.setExpandingEnabled(!onKeyguard);
+        ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
+        mStackScroller.setActivatedChild(null);
+        if (activatedChild != null) {
+            activatedChild.makeInactive(false /* animate */);
+        }
     }
 
     public void userActivity() {
@@ -2954,22 +2981,9 @@
 
     private void instantExpandNotificationsPanel() {
 
-        // Make our window larger and the panel visible.
+        // Make our window larger and the panel expanded.
         makeExpandedVisible(true);
-        mNotificationPanel.setVisibility(View.VISIBLE);
-
-        // Wait for window manager to pickup the change, so we know the maximum height of the panel
-        // then.
-        mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
-                new ViewTreeObserver.OnGlobalLayoutListener() {
-            @Override
-            public void onGlobalLayout() {
-                if (mStatusBarWindow.getHeight() != getStatusBarHeight()) {
-                    mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                    mNotificationPanel.setExpandedFraction(1);
-                }
-            }
-        });
+        mNotificationPanel.instantExpand();
     }
 
     private void instantCollapseNotificationPanel() {
@@ -2977,9 +2991,13 @@
     }
 
     @Override
-    public void onActivated(View view) {
+    public void onActivated(ActivatableNotificationView view) {
         userActivity();
         mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
+        ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
+        if (previousView != null) {
+            previousView.makeInactive(true /* animate */);
+        }
         mStackScroller.setActivatedChild(view);
     }
 
@@ -2992,7 +3010,7 @@
     }
 
     @Override
-    public void onActivationReset(View view) {
+    public void onActivationReset(ActivatableNotificationView view) {
         if (view == mStackScroller.getActivatedChild()) {
             mKeyguardIndicationController.hideTransientIndication();
             mStackScroller.setActivatedChild(null);
@@ -3123,4 +3141,41 @@
             }
         }
     };
+
+    // Recents
+
+    @Override
+    protected void showRecents(boolean triggeredFromAltTab) {
+        // Set the recents visibility flag
+        mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
+        notifyUiVisibilityChanged(mSystemUiVisibility);
+        super.showRecents(triggeredFromAltTab);
+    }
+
+    @Override
+    protected void hideRecents(boolean triggeredFromAltTab) {
+        // Unset the recents visibility flag
+        mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
+        notifyUiVisibilityChanged(mSystemUiVisibility);
+        super.hideRecents(triggeredFromAltTab);
+    }
+
+    @Override
+    protected void toggleRecents() {
+        // Toggle the recents visibility flag
+        mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
+        notifyUiVisibilityChanged(mSystemUiVisibility);
+        super.toggleRecents();
+    }
+
+    @Override
+    public void onVisibilityChanged(boolean visible) {
+        // Update the recents visibility flag
+        if (visible) {
+            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
+        } else {
+            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
+        }
+        notifyUiVisibilityChanged(mSystemUiVisibility);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index c8ab027..1712124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -70,6 +70,8 @@
 
     private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT;
     private int mNormalWidth;
+    private int mPadding;
+    private int mMultiUserExpandedMargin;
 
     private ActivityStarter mActivityStarter;
     private BrightnessController mBrightnessController;
@@ -120,6 +122,10 @@
         mKeyguardHeight = getResources().getDimensionPixelSize(
                 R.dimen.status_bar_header_height_keyguard);
         mNormalWidth = getLayoutParams().width;
+        mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding);
+        mMultiUserExpandedMargin =
+                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
+
     }
 
     public void setActivityStarter(ActivityStarter activityStarter) {
@@ -147,6 +153,8 @@
             updateZTranslation();
             updateClickTargets();
             updateWidth();
+            updatePadding();
+            updateMultiUserSwitch();
             if (mQSPanel != null) {
                 mQSPanel.setExpanded(expanded && !overscrolled);
             }
@@ -256,6 +264,21 @@
         }
     }
 
+    private void updatePadding() {
+        boolean padded = !mKeyguardShowing || mExpanded;
+        int padding = padded ? mPadding : 0;
+        setPaddingRelative(padding, 0, padding, 0);
+    }
+
+    private void updateMultiUserSwitch() {
+        int marginEnd = !mKeyguardShowing || mExpanded ? mMultiUserExpandedMargin : 0;
+        MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
+        if (marginEnd != lp.getMarginEnd()) {
+            lp.setMarginEnd(marginEnd);
+            mMultiUserSwitch.setLayoutParams(lp);
+        }
+    }
+
     public void setExpansion(float height) {
         height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight;
         if (height < mCollapsedHeight) {
@@ -301,6 +324,8 @@
         updateWidth();
         updateVisibilities();
         updateZTranslation();
+        updatePadding();
+        updateMultiUserSwitch();
     }
 
     public void setUserInfoController(UserInfoController userInfoController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index df01c12..0a48e34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -33,9 +33,9 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
-import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback,
         ViewTreeObserver.OnComputeInternalInsetsListener {
@@ -51,7 +51,7 @@
     private SwipeHelper mSwipeHelper;
     private EdgeSwipeHelper mEdgeSwipeHelper;
 
-    private BaseStatusBar mBar;
+    private PhoneStatusBar mBar;
     private ExpandHelper mExpandHelper;
 
     private long mStartTouchTime;
@@ -69,7 +69,7 @@
         if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
     }
 
-    public void setBar(BaseStatusBar bar) {
+    public void setBar(PhoneStatusBar bar) {
         mBar = bar;
     }
 
@@ -77,7 +77,12 @@
         return mContentHolder;
     }
 
-    public boolean setNotification(NotificationData.Entry headsUp) {
+    public boolean showNotification(NotificationData.Entry headsUp) {
+        if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) {
+            // bump any previous heads up back to the shade
+            release();
+        }
+
         mHeadsUp = headsUp;
         if (mContentHolder != null) {
             mContentHolder.removeAllViews();
@@ -97,10 +102,57 @@
 
             mSwipeHelper.snapChild(mContentHolder, 1f);
             mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+
+            mHeadsUp.setInterruption();
+
+            // 2. Animate mHeadsUpNotificationView in
+            mBar.scheduleHeadsUpOpen();
+
+            // 3. Set alarm to age the notification off
+            mBar.resetHeadsUpDecayTimer();
         }
         return true;
     }
 
+    public boolean isShowing(String key) {
+        return mHeadsUp != null && mHeadsUp.key.equals(key);
+    }
+
+    /** Discard the Heads Up notification. */
+    public void clear() {
+        mHeadsUp = null;
+        mBar.scheduleHeadsUpClose();
+    }
+
+    /** Respond to dismissal of the Heads Up window. */
+    public void dismiss() {
+        if (mHeadsUp == null) return;
+        if (mHeadsUp.notification.isClearable()) {
+            mBar.onNotificationClear(mHeadsUp.notification);
+        } else {
+            release();
+        }
+        mHeadsUp = null;
+        mBar.scheduleHeadsUpClose();
+    }
+
+    /** Push any current Heads Up notification down into the shade. */
+    public void release() {
+        if (mHeadsUp != null) {
+            mBar.displayNotificationFromHeadsUp(mHeadsUp.notification);
+        }
+        mHeadsUp = null;
+    }
+
+    public void releaseAndClose() {
+        release();
+        mBar.scheduleHeadsUpClose();
+    }
+
+    public NotificationData.Entry getEntry() {
+        return mHeadsUp;
+    }
+
     public boolean isClearable() {
         return mHeadsUp == null || mHeadsUp.notification.isClearable();
     }
@@ -125,7 +177,7 @@
 
         if (mHeadsUp != null) {
             // whoops, we're on already!
-            setNotification(mHeadsUp);
+            showNotification(mHeadsUp);
         }
 
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
@@ -282,6 +334,10 @@
                 mTmpTwoArray[1] + mContentHolder.getHeight());
     }
 
+    public void escalate() {
+        mBar.scheduleHeadsUpEscalation();
+    }
+
     private class EdgeSwipeHelper implements Gefingerpoken {
         private static final boolean DEBUG_EDGE_SWIPE = false;
         private final float mTouchSlop;
@@ -335,4 +391,4 @@
             return mConsuming;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index dc8f315..1f68860 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -30,7 +30,7 @@
         void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
                 String mobileSignalContentDescriptionId, int dataTypeIconId,
                 boolean activityIn, boolean activityOut,
-                String dataTypeContentDescriptionId, String description);
+                String dataTypeContentDescriptionId, String description, boolean noSim);
         void onAirplaneModeChanged(boolean enabled);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index bf908fe..4e54e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -88,6 +88,7 @@
     int mQSDataTypeIconId;
     int mAirplaneIconId;
     boolean mDataActive;
+    boolean mNoSim;
     int mLastSignalLevel;
     boolean mShowPhoneRSSIForData = false;
     boolean mShowAtLeastThreeGees = false;
@@ -350,18 +351,18 @@
         if (isEmergencyOnly()) {
             cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
                     mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                    mContentDescriptionDataType, null);
+                    mContentDescriptionDataType, null, mNoSim);
         } else {
             if (mIsWimaxEnabled && mWimaxConnected) {
                 // Wimax is special
                 cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
                         mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName);
+                        mContentDescriptionDataType, mNetworkName, mNoSim);
             } else {
                 // Normal mobile data
                 cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
                         mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName);
+                        mContentDescriptionDataType, mNetworkName, mNoSim);
             }
         }
         cb.onAirplaneModeChanged(mAirplaneMode);
@@ -737,6 +738,7 @@
             // GSM case, we have to check also the sim state
             if (mSimState == IccCardConstants.State.READY ||
                     mSimState == IccCardConstants.State.UNKNOWN) {
+                mNoSim = false;
                 if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
                     switch (mDataActivity) {
                         case TelephonyManager.DATA_ACTIVITY_IN:
@@ -759,6 +761,7 @@
                 }
             } else {
                 iconId = R.drawable.stat_sys_no_sim;
+                mNoSim = true;
                 visible = false; // no SIM? no data
             }
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index b21e12c..6d92b05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.stack;
 
 import android.view.View;
+import com.android.systemui.statusbar.ActivatableNotificationView;
 
 import java.util.ArrayList;
 
@@ -27,7 +28,7 @@
     private ArrayList<View> mDraggedViews = new ArrayList<View>();
     private int mScrollY;
     private boolean mDimmed;
-    private View mActivatedChild;
+    private ActivatableNotificationView mActivatedChild;
     private float mOverScrollTopAmount;
     private float mOverScrollBottomAmount;
     private int mSpeedBumpIndex = -1;
@@ -64,7 +65,7 @@
      * 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) {
+    public void setActivatedChild(ActivatableNotificationView activatedChild) {
         mActivatedChild = activatedChild;
     }
 
@@ -72,7 +73,7 @@
         return mDimmed;
     }
 
-    public View getActivatedChild() {
+    public ActivatableNotificationView getActivatedChild() {
         return mActivatedChild;
     }
 
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 5ace89f..ccbaed3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -33,6 +33,7 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
@@ -240,11 +241,12 @@
         mBottomStackPeekSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
         mStackScrollAlgorithm = new StackScrollAlgorithm(context);
+        mStackScrollAlgorithm.setDimmed(mAmbientState.isDimmed());
         mPaddingBetweenElementsDimmed = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
         mPaddingBetweenElementsNormal = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_padding);
-        updatePadding(false);
+        updatePadding(mAmbientState.isDimmed());
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
         mExpandHelper = new ExpandHelper(getContext(), this,
@@ -760,11 +762,12 @@
                                 }
                             }
                         }
-
-                        mActivePointerId = INVALID_POINTER;
-                        endDrag();
                     }
+
+                    mActivePointerId = INVALID_POINTER;
+                    endDrag();
                 }
+
                 break;
             case MotionEvent.ACTION_CANCEL:
                 if (mIsBeingDragged && getChildCount() > 0) {
@@ -966,7 +969,7 @@
      * @param animate Should an animation be performed.
      */
     public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
-        setOverScrollAmount(numPixels * getRubberBandFactor(), onTop, animate, true);
+        setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true);
     }
 
     /**
@@ -1002,7 +1005,7 @@
         if (animate) {
             mStateAnimator.animateOverScrollToAmount(amount, onTop);
         } else {
-            setOverScrolledPixels(amount / getRubberBandFactor(), onTop);
+            setOverScrolledPixels(amount / getRubberBandFactor(onTop), onTop);
             mAmbientState.setOverScrollAmount(amount, onTop);
             if (onTop) {
                 notifyOverscrollTopListener(amount);
@@ -1224,13 +1227,14 @@
                 mOwnScrollY -= (int) topAmount;
                 mDontReportNextOverScroll = true;
                 setOverScrollAmount(0, true, false);
-                mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor()
+                mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
                         * mOverflingDistance + topAmount;
             } else if (velocityY > 0 && bottomAmount > 0) {
                 mOwnScrollY += bottomAmount;
                 setOverScrollAmount(0, false, false);
-                mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor()
-                        * mOverflingDistance + bottomAmount;
+                mMaxOverScroll = Math.abs(velocityY) / 1000f
+                        * getRubberBandFactor(false /* onTop */) * mOverflingDistance
+                        +  bottomAmount;
             } else {
                 // it will be set once we reach the boundary
                 mMaxOverScroll = 0.0f;
@@ -1272,7 +1276,10 @@
         return Math.max(desiredPadding, mIntrinsicPadding);
     }
 
-    private float getRubberBandFactor() {
+    private float getRubberBandFactor(boolean onTop) {
+        if (!onTop) {
+            return RUBBER_BAND_FACTOR_NORMAL;
+        }
         if (mExpandedInThisMotion) {
             return RUBBER_BAND_FACTOR_AFTER_EXPAND;
         } else if (mIsExpansionChanging) {
@@ -1722,7 +1729,6 @@
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
         if (!isExpanded) {
             mOwnScrollY = 0;
-            mSpeedBumpView.collapse();
         }
     }
 
@@ -1760,7 +1766,7 @@
     /**
      * See {@link AmbientState#setActivatedChild}.
      */
-    public void setActivatedChild(View activatedChild) {
+    public void setActivatedChild(ActivatableNotificationView activatedChild) {
         mAmbientState.setActivatedChild(activatedChild);
         if (mAnimationsEnabled) {
             mActivateNeedsAnimation = true;
@@ -1769,7 +1775,7 @@
         requestChildrenUpdate();
     }
 
-    public View getActivatedChild() {
+    public ActivatableNotificationView getActivatedChild() {
         return mAmbientState.getActivatedChild();
     }
 
@@ -1791,7 +1797,6 @@
             int newVisibility = visible ? VISIBLE : GONE;
             mSpeedBumpView.setVisibility(newVisibility);
             if (visible) {
-                mSpeedBumpView.collapse();
                 // Make invisible to ensure that the appear animation is played.
                 mSpeedBumpView.setInvisible();
                 if (!mIsExpansionChanging) {
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 d6ff4fc..602c22b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -186,7 +186,7 @@
             if (!child.isTransparent()) {
                 // Only update the previous values if we are not transparent,
                 // otherwise we would clip to a transparent view.
-                previousNotificationStart = newYTranslation + child.getClipTopAmount();
+                previousNotificationStart = newYTranslation + state.clipTopAmount;
                 previousNotificationEnd = newNotificationEnd;
                 previousNotificationIsSwiped = child.getTranslationX() != 0;
             }
@@ -587,6 +587,7 @@
                     algorithmState.itemsInTopStack += algorithmState.partialInTop;
                     newSize = Math.max(mCollapsedSize, newSize);
                     if (i == 0) {
+                        algorithmState.itemsInTopStack = 1.0f;
                         childViewState.height = (int) newSize;
                     }
                     algorithmState.lastTopStackIndex = i;
@@ -617,6 +618,20 @@
             if (i < algorithmState.itemsInTopStack) {
                 float stackIndex = algorithmState.itemsInTopStack - i;
                 stackIndex = Math.min(stackIndex, MAX_ITEMS_IN_TOP_STACK + 2);
+                if (i == 0 && algorithmState.itemsInTopStack < 2.0f) {
+
+                    // We only have the top item and an additional item in the top stack,
+                    // Interpolate the index from 0 to 2 while the second item is
+                    // translating in.
+                    stackIndex -= 1.0f;
+                    if (algorithmState.scrollY > mCollapsedSize) {
+
+                        // Since there is a shadow treshhold, we cant just interpolate from 0 to
+                        // 2 but we interpolate from 0.1f to 2.0f when scrolled in. The jump in
+                        // height will not be noticable since we have padding in between.
+                        stackIndex = 0.1f + stackIndex * 1.9f;
+                    }
+                }
                 childViewState.zTranslation = mZBasicHeight
                         + stackIndex * mZDistanceBetweenElements;
             } else if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
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 94cb16d..1ad4acc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -160,9 +160,8 @@
                 }
 
                 if(child instanceof SpeedBumpView) {
-                    float speedBumpEnd = newYTranslation + newHeight;
-                    performSpeedBumpAnimation(i, (SpeedBumpView) child, speedBumpEnd,
-                            newYTranslation);
+                    float lineEnd = newYTranslation + newHeight / 2;
+                    performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd);
                 }
             }
         }
@@ -183,20 +182,12 @@
         child.setClipBounds(mClipRect);
     }
 
-    private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
-            float speedBumpStart) {
+    private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd) {
         View nextChild = getNextChildNotGone(i);
         if (nextChild != null) {
             ViewState nextState = getViewStateForView(nextChild);
-            boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+            boolean startIsAboveNext = nextState.yTranslation > speedBumpEnd;
             speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */);
-
-            // handle expanded case
-            if (speedBump.isExpanded()) {
-                boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
-                speedBump.animateExplanationText(endIsAboveNext);
-            }
-
         }
     }
 
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 faea8de..9260aac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,14 +17,14 @@
 package com.android.systemui.statusbar.tv;
 
 import android.os.IBinder;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BaseStatusBar;
 
 /*
@@ -51,11 +51,11 @@
     }
 
     @Override
-    public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+    public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
     }
 
     @Override
-    protected void updateRankingInternal(Ranking ranking) {
+    protected void updateRankingInternal(RankingMap ranking) {
     }
 
     @Override
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public void removeNotificationInternal(String key, Ranking ranking) {
+    public void removeNotificationInternal(String key, RankingMap ranking) {
     }
 
     @Override
@@ -147,6 +147,18 @@
     }
 
     @Override
+    public void scheduleHeadsUpOpen() {
+    }
+
+    @Override
+    public void scheduleHeadsUpEscalation() {
+    }
+
+    @Override
+    public void scheduleHeadsUpClose() {
+    }
+
+    @Override
     protected int getMaxKeyguardNotifications() {
         return 0;
     }
@@ -164,10 +176,10 @@
     }
 
     @Override
-    public void onActivated(View view) {
+    public void onActivated(ActivatableNotificationView view) {
     }
 
     @Override
-    public void onActivationReset(View view) {
+    public void onActivationReset(ActivatableNotificationView view) {
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index b2ecb61..4ad45a8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -40,9 +40,6 @@
     private static String TAG = "PhoneFallbackEventHandler";
     private static final boolean DEBUG = false;
 
-    // Use the new sessions APIs
-    private static final boolean USE_SESSIONS = true;
-
     Context mContext;
     View mView;
 
@@ -294,21 +291,7 @@
     }
 
     private void handleMediaKeyEvent(KeyEvent keyEvent) {
-        if (USE_SESSIONS) {
-            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
-        } else {
-            IAudioService audioService = IAudioService.Stub.asInterface(
-                    ServiceManager.checkService(Context.AUDIO_SERVICE));
-            if (audioService != null) {
-                try {
-                    audioService.dispatchMediaKeyEvent(keyEvent);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
-                }
-            } else {
-                Slog.w(TAG, "Unable to find IAudioService for media key event.");
-            }
-        }
+        MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
     }
 }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a8645bc..5e1aa3b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -93,6 +93,7 @@
 import android.view.ViewRootImpl;
 import android.view.ViewStub;
 import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -118,6 +119,9 @@
     private final static String TAG = "PhoneWindow";
 
     private final static boolean SWEEP_OPEN_MENU = false;
+
+    private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
+
     /**
      * Simple callback used by the context menu and its submenus. The options
      * menu submenus do not use this (their behavior is more complex).
@@ -246,6 +250,7 @@
     private Transition mSharedElementExitTransition;
     private Boolean mAllowExitTransitionOverlap;
     private Boolean mAllowEnterTransitionOverlap;
+    private long mBackgroundFadeDurationMillis = -1;
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2627,15 +2632,15 @@
         }
 
         @Override
-        protected boolean fitSystemWindows(Rect insets) {
-            mFrameOffsets.set(insets);
+        public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+            mFrameOffsets.set(insets.getSystemWindowInsets());
             updateColorViews(insets);
-            updateStatusGuard(insets);
+            insets = updateStatusGuard(insets);
             updateNavigationGuard(insets);
             if (getForeground() != null) {
                 drawableChanged();
             }
-            return super.fitSystemWindows(insets);
+            return insets;
         }
 
         @Override
@@ -2643,14 +2648,14 @@
             return false;
         }
 
-        private void updateColorViews(Rect insets) {
+        private void updateColorViews(WindowInsets insets) {
             if (mIsFloating || !ActivityManager.isHighEndGfx()) {
                 // No colors on floating windows or low end devices :(
                 return;
             }
             if (insets != null) {
-                mLastTopInset = insets.top;
-                mLastBottomInset = insets.bottom;
+                mLastTopInset = insets.getSystemWindowInsetTop();
+                mLastBottomInset = insets.getSystemWindowInsetBottom();
             }
             mStatusColorView = updateColorViewInt(mStatusColorView,
                     SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
@@ -2689,7 +2694,7 @@
             return view;
         }
 
-        private void updateStatusGuard(Rect insets) {
+        private WindowInsets updateStatusGuard(WindowInsets insets) {
             boolean showStatusGuard = false;
             // Show the status guard when the non-overlay contextual action bar is showing
             if (mActionModeView != null) {
@@ -2701,9 +2706,9 @@
                             && mActionModeView.isShown();
                     if (nonOverlayShown) {
                         // set top margin to top insets, show status guard
-                        if (mlp.topMargin != insets.top) {
+                        if (mlp.topMargin != insets.getSystemWindowInsetTop()) {
                             mlpChanged = true;
-                            mlp.topMargin = insets.top;
+                            mlp.topMargin = insets.getSystemWindowInsetTop();
                             if (mStatusGuard == null) {
                                 mStatusGuard = new View(mContext);
                                 mStatusGuard.setBackgroundColor(mContext.getResources()
@@ -2719,7 +2724,8 @@
                                 }
                             }
                         }
-                        insets.top = 0;  // consume top insets
+                        insets = insets.consumeSystemWindowInsets(
+                                false, true /* top */, false, false);
                         showStatusGuard = true;
                     } else {
                         // reset top margin
@@ -2736,9 +2742,10 @@
             if (mStatusGuard != null) {
                 mStatusGuard.setVisibility(showStatusGuard ? View.VISIBLE : View.GONE);
             }
+            return insets;
         }
 
-        private void updateNavigationGuard(Rect insets) {
+        private void updateNavigationGuard(WindowInsets insets) {
             // IMEs lay out below the nav bar, but the content view must not (for back compat)
             if (getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
                 // prevent the content view from including the nav bar height
@@ -2746,7 +2753,7 @@
                     if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
                         MarginLayoutParams mlp =
                                 (MarginLayoutParams) mContentParent.getLayoutParams();
-                        mlp.bottomMargin = insets.bottom;
+                        mlp.bottomMargin = insets.getSystemWindowInsetBottom();
                         mContentParent.setLayoutParams(mlp);
                     }
                 }
@@ -2756,11 +2763,11 @@
                     mNavigationGuard.setBackgroundColor(mContext.getResources()
                             .getColor(R.color.input_method_navigation_guard));
                     addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams(
-                            LayoutParams.MATCH_PARENT, insets.bottom,
+                            LayoutParams.MATCH_PARENT, insets.getSystemWindowInsetBottom(),
                             Gravity.START | Gravity.BOTTOM));
                 } else {
                     LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
-                    lp.height = insets.bottom;
+                    lp.height = insets.getSystemWindowInsetBottom();
                     mNavigationGuard.setLayoutParams(lp);
                 }
             }
@@ -3419,6 +3426,12 @@
                             com.android.internal.R.styleable.
                                     Window_windowAllowExitTransitionOverlap, true);
                 }
+                if (mBackgroundFadeDurationMillis < 0) {
+                    mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
+                            com.android.internal.R.styleable.
+                                    Window_windowTransitionBackgroundFadeDuration,
+                            DEFAULT_BACKGROUND_FADE_DURATION_MS);
+                }
             }
         }
     }
@@ -3825,6 +3838,20 @@
         return (mAllowExitTransitionOverlap == null) ? true : mAllowExitTransitionOverlap;
     }
 
+    @Override
+    public long getTransitionBackgroundFadeDuration() {
+        return (mBackgroundFadeDurationMillis < 0) ? DEFAULT_BACKGROUND_FADE_DURATION_MS
+                : mBackgroundFadeDurationMillis;
+    }
+
+    @Override
+    public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) {
+        if (fadeDurationMillis < 0) {
+            throw new IllegalArgumentException("negative durations are not allowed");
+        }
+        mBackgroundFadeDurationMillis = fadeDurationMillis;
+    }
+
     private static final class DrawableFeatureState {
         DrawableFeatureState(int _featureId) {
             featureId = _featureId;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 03d29c0..bc2671011 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -144,9 +144,6 @@
     static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
     static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
 
-    // Whether to use the new Session APIs
-    static final boolean USE_SESSIONS = true;
-
     static final int SHORT_PRESS_POWER_NOTHING = 0;
     static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -296,6 +293,7 @@
     WindowState mLastInputMethodWindow = null;
     WindowState mLastInputMethodTargetWindow = null;
 
+    boolean mRecentsVisible;
     int mRecentAppsHeldModifiers;
     boolean mLanguageSwitchKeyPressed;
 
@@ -305,6 +303,7 @@
     boolean mSystemReady;
     boolean mSystemBooted;
     boolean mHdmiPlugged;
+    IUiModeManager mUiModeManager;
     int mUiMode;
     int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     int mLidOpenRotation;
@@ -434,6 +433,12 @@
      * be done once per window. */
     private WindowState mWinDismissingKeyguard;
 
+    /** The window that is currently showing "over" the keyguard. If there is an app window
+     * belonging to another app on top of this the keyguard shows. If there is a fullscreen
+     * app window under this, still dismiss the keyguard but don't show the app underneath. Show
+     * the wallpaper. */
+    private WindowState mWinShowWhenLocked;
+
     boolean mShowingLockscreen;
     boolean mShowingDream;
     boolean mDreamingLockscreen;
@@ -1668,8 +1673,9 @@
     }
 
     @Override
-    public boolean doesForceHide(WindowManager.LayoutParams attrs) {
-        return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+    public boolean isForceHiding(WindowManager.LayoutParams attrs) {
+        return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
+                (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden());
     }
 
     @Override
@@ -2632,6 +2638,11 @@
                     }
                 }
             });
+        } else if (mRecentsVisible) {
+            // Recents is started on top of Home, so when we launch home while recents is open, let
+            // it do its own animation and then finish itself
+            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+            hideRecentApps(false);
         } else {
             // no keyguard stuff to worry about, just launch home!
             try {
@@ -2723,6 +2734,7 @@
     public int adjustSystemUiVisibilityLw(int visibility) {
         mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
         mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+        mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
 
         // Reset any bits in mForceClearingStatusBarVisibility that
         // are now clear.
@@ -3112,10 +3124,11 @@
 
     /** {@inheritDoc} */
     @Override
-    public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
-            WindowState attached) {
+    public void layoutWindowLw(WindowState win, WindowState attached) {
         // we've already done the status bar
-        if ((win == mStatusBar && !doesForceHide(attrs)) || win == mNavigationBar) {
+        final WindowManager.LayoutParams attrs = win.getAttrs();
+        if ((win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) == 0) ||
+                win == mNavigationBar) {
             return;
         }
         final boolean isDefaultDisplay = win.isDefaultDisplay();
@@ -3596,12 +3609,12 @@
         mDismissKeyguard = DISMISS_KEYGUARD_NONE;
         mShowingLockscreen = false;
         mShowingDream = false;
+        mWinShowWhenLocked = null;
     }
 
     /** {@inheritDoc} */
     @Override
-    public void applyPostLayoutPolicyLw(WindowState win,
-                                WindowManager.LayoutParams attrs) {
+    public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs) {
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
                 + win.isVisibleOrBehindKeyguardLw());
         final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -3639,9 +3652,17 @@
 
             final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
             final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
+            final boolean secureKeyguard = isKeyguardSecure();
             if (appWindow) {
-                if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
+                if (showWhenLocked || (dismissKeyguard && !secureKeyguard)) {
+                    // Remove any previous windows with the same appToken.
                     mAppsToBeHidden.remove(win.getAppToken());
+                    if (mAppsToBeHidden.isEmpty() && showWhenLocked &&
+                            isKeyguardSecureIncludingHidden()) {
+                        mWinShowWhenLocked = win;
+                        mHideLockScreen = true;
+                        mForceStatusBarFromKeyguard = false;
+                    }
                 } else {
                     mAppsToBeHidden.add(win.getAppToken());
                 }
@@ -3663,13 +3684,18 @@
                             mDismissKeyguard = mWinDismissingKeyguard == win ?
                                     DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                             mWinDismissingKeyguard = win;
-                            mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
+                            mForceStatusBarFromKeyguard = mShowingLockscreen && secureKeyguard;
                         }
                     }
                     if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
                         mAllowLockscreenWhenOn = true;
                     }
                 }
+
+                if (mWinShowWhenLocked != null &&
+                        mWinShowWhenLocked.getAppToken() != win.getAppToken()) {
+                    win.hideLw(false);
+                }
             }
         }
     }
@@ -3677,6 +3703,16 @@
     /** {@inheritDoc} */
     @Override
     public int finishPostLayoutPolicyLw() {
+        if (mWinShowWhenLocked != null &&
+                mWinShowWhenLocked != mTopFullscreenOpaqueWindowState) {
+            // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the
+            // fullscreen window.
+            // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not.
+            mWinShowWhenLocked.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+            mTopFullscreenOpaqueWindowState.hideLw(false);
+            mTopFullscreenOpaqueWindowState = mWinShowWhenLocked;
+        }
+
         int changes = 0;
         boolean topIsFullscreen = false;
 
@@ -3935,6 +3971,7 @@
      *    controlled by this device, or through remote submix).
      */
     boolean isMusicActive() {
+
         final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
         if (am == null) {
             Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
@@ -3943,43 +3980,6 @@
         return am.isLocalOrRemoteMusicActive();
     }
 
-    /**
-     * Tell the audio service to adjust the volume appropriate to the event.
-     * @param keycode
-     */
-    void handleVolumeKey(int stream, int keycode) {
-        IAudioService audioService = getAudioService();
-        if (audioService == null) {
-            return;
-        }
-        try {
-            // when audio is playing locally, we shouldn't have to hold a wake lock
-            // during the call, but we do it as a precaution for the rare possibility
-            // that the music stops right before we call this.
-            // Otherwise we might also be in a remote playback case.
-            // TODO: Actually handle MUTE.
-            mBroadcastWakeLock.acquire();
-            if (stream == AudioSystem.STREAM_MUSIC) {
-                audioService.adjustLocalOrRemoteStreamVolume(stream,
-                        keycode == KeyEvent.KEYCODE_VOLUME_UP
-                                ? AudioManager.ADJUST_RAISE
-                                : AudioManager.ADJUST_LOWER,
-                        mContext.getOpPackageName());
-            } else {
-                audioService.adjustStreamVolume(stream,
-                        keycode == KeyEvent.KEYCODE_VOLUME_UP
-                                ? AudioManager.ADJUST_RAISE
-                                : AudioManager.ADJUST_LOWER,
-                        0,
-                        mContext.getOpPackageName());
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "IAudioService.adjust*StreamVolume() threw RemoteException " + e);
-        } finally {
-            mBroadcastWakeLock.release();
-        }
-    }
-
     final Object mScreenshotLock = new Object();
     ServiceConnection mScreenshotConnection = null;
 
@@ -4079,11 +4079,6 @@
                     + " policyFlags=" + Integer.toHexString(policyFlags));
         }
 
-        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
-                && event.getRepeatCount() == 0) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-
         // Basic policy based on interactive state.
         int result;
         boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
@@ -4106,6 +4101,10 @@
             return result;
         }
 
+        boolean useHapticFeedback = down
+                && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+                && event.getRepeatCount() == 0;
+
         // Handle special keys.
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -4163,16 +4162,20 @@
                         if (telephonyManager.isOffhook()
                                 && (result & ACTION_PASS_TO_USER) == 0) {
                             // If we are in call but we decided not to pass the key to
-                            // the application, handle the volume change here.
-                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
+                            // the application, just pass it to the session service.
+
+                            MediaSessionLegacyHelper.getHelper(mContext)
+                                    .sendMediaButtonEvent(event, true);
                             break;
                         }
                     }
 
-                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
-                        // If music is playing but we decided not to pass the key to the
-                        // application, handle the volume change here.
-                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+                    if ((result & ACTION_PASS_TO_USER) == 0) {
+                        // If we aren't passing to the user and no one else
+                        // handled it send it to the session manager to figure
+                        // out.
+                        MediaSessionLegacyHelper.getHelper(mContext)
+                                .sendMediaButtonEvent(event, true);
                         break;
                     }
                 }
@@ -4252,6 +4255,9 @@
 
             case KeyEvent.KEYCODE_SLEEP: {
                 result &= ~ACTION_PASS_TO_USER;
+                if (!mPowerManager.isInteractive()) {
+                    useHapticFeedback = false; // suppress feedback if already non-interactive
+                }
                 mPowerManager.goToSleep(event.getEventTime());
                 isWakeKey = false;
                 break;
@@ -4318,6 +4324,10 @@
             }
         }
 
+        if (useHapticFeedback) {
+            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+        }
+
         if (isWakeKey) {
             mPowerManager.wakeUp(event.getEventTime());
         }
@@ -4414,18 +4424,7 @@
 
     void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
         if (ActivityManagerNative.isSystemReady()) {
-            if (USE_SESSIONS) {
-                MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
-            } else {
-                IAudioService audioService = getAudioService();
-                if (audioService != null) {
-                    try {
-                        audioService.dispatchMediaKeyEventUnderWakelock(event);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
-                    }
-                }
-            }
+            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
         }
     }
 
@@ -4632,6 +4631,11 @@
         return mKeyguardDelegate.isSecure();
     }
 
+    // Returns true if keyguard is currently locked whether or not it is currently hidden.
+    private boolean isKeyguardSecureIncludingHidden() {
+        return mKeyguardDelegate.isSecure() && mKeyguardDelegate.isShowing();
+    }
+
     /** {@inheritDoc} */
     public boolean inKeyguardRestrictedKeyInputMode() {
         if (mKeyguardDelegate == null) return false;
@@ -4941,6 +4945,7 @@
         mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
         mKeyguardDelegate.onSystemReady();
 
+        updateUiMode();
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
@@ -5129,6 +5134,17 @@
         }
     }
 
+    void updateUiMode() {
+        if (mUiModeManager == null) {
+            mUiModeManager = IUiModeManager.Stub.asInterface(
+                    ServiceManager.getService(Context.UI_MODE_SERVICE));
+        }
+        try {
+            mUiMode = mUiModeManager.getCurrentModeType();
+        } catch (RemoteException e) {
+        }
+    }
+
     void updateRotation(boolean alwaysSendConfiguration) {
         try {
             //set orientation on WindowManager
@@ -5174,6 +5190,12 @@
             if (ENABLE_DESK_DOCK_HOME_CAPTURE) {
                 intent = mDeskDockIntent;
             }
+        } else if (mUiMode == Configuration.UI_MODE_TYPE_WATCH
+                && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+                        || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK
+                        || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK)) {
+            // Always launch dock home from home when watch is docked, if it exists.
+            intent = mDeskDockIntent;
         }
 
         if (intent == null) {
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 0e57232..c9bba69 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -233,6 +233,9 @@
         if (obj != null) {
             if (RenderScript.sPointerSize == 8) {
                 addI64(obj.getID(null));
+                addI64(0);
+                addI64(0);
+                addI64(0);
             }
             else {
                 addI32((int)obj.getID(null));
@@ -240,6 +243,9 @@
         } else {
             if (RenderScript.sPointerSize == 8) {
                 addI64(0);
+                addI64(0);
+                addI64(0);
+                addI64(0);
             } else {
                 addI32(0);
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index eca1bc1..1be1572 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1640,6 +1640,17 @@
                 pw.println("}]");
                 pw.println();
             }
+            final int windowCount = mSecurityPolicy.mWindows.size();
+            for (int j = 0; j < windowCount; j++) {
+                if (j > 0) {
+                    pw.append(',');
+                    pw.println();
+                }
+                pw.append("Window[");
+                AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(j);
+                pw.append(window.toString());
+                pw.append(']');
+            }
         }
     }
 
@@ -3283,7 +3294,7 @@
                 }
 
                 if (mTouchInteractionInProgress && activeWindowGone) {
-                    mActiveWindowId = INVALID_WINDOW_ID;
+                    mActiveWindowId = mFocusedWindowId;
                 }
 
                 // Focused window may change the active one, so set the
@@ -3291,7 +3302,7 @@
                 for (int i = 0; i < windowCount; i++) {
                     AccessibilityWindowInfo window = mWindows.get(i);
                     if (window.getId() == mActiveWindowId) {
-                       window.setActive(true);
+                        window.setActive(true);
                     }
                 }
             }
@@ -3336,10 +3347,11 @@
                     // The active window also determined events from which
                     // windows are delivered.
                     synchronized (mLock) {
-                        mFocusedWindowId = getFocusedWindowId();
-                        if (mWindowsForAccessibilityCallback == null
-                                && windowId == mFocusedWindowId) {
-                            mActiveWindowId = windowId;
+                        if (mWindowsForAccessibilityCallback == null) {
+                            mFocusedWindowId = getFocusedWindowId();
+                            if (windowId == mFocusedWindowId) {
+                                mActiveWindowId = windowId;
+                            }
                         }
                     }
                 } break;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 14c15a7..3b1e88a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -28,6 +28,7 @@
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupTransport;
 import android.app.backup.FullBackup;
+import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
 import android.app.backup.IBackupManager;
 import android.app.backup.IFullBackupRestoreObserver;
@@ -201,7 +202,7 @@
     private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
     private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
     private static final int MSG_RUN_BACKUP = 1;
-    private static final int MSG_RUN_FULL_BACKUP = 2;
+    private static final int MSG_RUN_ADB_BACKUP = 2;
     private static final int MSG_RUN_RESTORE = 3;
     private static final int MSG_RUN_CLEAR = 4;
     private static final int MSG_RUN_INITIALIZE = 5;
@@ -209,10 +210,11 @@
     private static final int MSG_TIMEOUT = 7;
     private static final int MSG_RESTORE_TIMEOUT = 8;
     private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
-    private static final int MSG_RUN_FULL_RESTORE = 10;
+    private static final int MSG_RUN_ADB_RESTORE = 10;
     private static final int MSG_RETRY_INIT = 11;
     private static final int MSG_RETRY_CLEAR = 12;
     private static final int MSG_WIDGET_BROADCAST = 13;
+    private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
 
     // backup task state machine tick
     static final int MSG_BACKUP_RESTORE_STEP = 20;
@@ -448,11 +450,12 @@
         public boolean doWidgets;
         public boolean allApps;
         public boolean includeSystem;
+        public boolean doCompress;
         public String[] packages;
 
         FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
                 boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem,
-                String[] pkgList) {
+                boolean compress, String[] pkgList) {
             fd = output;
             includeApks = saveApks;
             includeObbs = saveObbs;
@@ -460,6 +463,7 @@
             doWidgets = alsoWidgets;
             allApps = doAllApps;
             includeSystem = doSystem;
+            doCompress = compress;
             packages = pkgList;
         }
     }
@@ -646,17 +650,25 @@
                 break;
             }
 
-            case MSG_RUN_FULL_BACKUP:
+            case MSG_RUN_ADB_BACKUP:
             {
                 // TODO: refactor full backup to be a looper-based state machine
                 // similar to normal backup/restore.
                 FullBackupParams params = (FullBackupParams)msg.obj;
-                PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
+                PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd,
                         params.observer, params.includeApks, params.includeObbs,
                         params.includeShared, params.doWidgets,
                         params.curPassword, params.encryptPassword,
-                        params.allApps, params.includeSystem, params.packages, params.latch);
-                (new Thread(task)).start();
+                        params.allApps, params.includeSystem, params.doCompress,
+                        params.packages, params.latch);
+                (new Thread(task, "adb-backup")).start();
+                break;
+            }
+
+            case MSG_RUN_FULL_TRANSPORT_BACKUP:
+            {
+                PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj;
+                (new Thread(task, "transport-backup")).start();
                 break;
             }
 
@@ -673,7 +685,7 @@
                 break;
             }
 
-            case MSG_RUN_FULL_RESTORE:
+            case MSG_RUN_ADB_RESTORE:
             {
                 // TODO: refactor full restore to be a looper-based state machine
                 // similar to normal backup/restore.
@@ -681,7 +693,7 @@
                 PerformFullRestoreTask task = new PerformFullRestoreTask(params.fd,
                         params.curPassword, params.encryptPassword,
                         params.observer, params.latch);
-                (new Thread(task)).start();
+                (new Thread(task, "adb-restore")).start();
                 break;
             }
 
@@ -2618,13 +2630,6 @@
 
     // ----- Full backup/restore to a file/socket -----
 
-    abstract class ObbServiceClient {
-        public IObbBackupService mObbService;
-        public void setObbBinder(IObbBackupService binder) {
-            mObbService = binder;
-        }
-    }
-
     class FullBackupObbConnection implements ServiceConnection {
         volatile IObbBackupService mService;
 
@@ -2736,24 +2741,15 @@
         }
     }
 
-    class PerformFullBackupTask extends ObbServiceClient implements Runnable {
-        ParcelFileDescriptor mOutputFile;
-        DeflaterOutputStream mDeflater;
+    // Core logic for performing one package's full backup, gathering the tarball from the
+    // application and emitting it to the designated OutputStream.
+    class FullBackupEngine {
+        OutputStream mOutput;
         IFullBackupRestoreObserver mObserver;
-        boolean mIncludeApks;
-        boolean mIncludeObbs;
-        boolean mIncludeShared;
-        boolean mDoWidgets;
-        boolean mAllApps;
-        final boolean mIncludeSystem;
-        ArrayList<String> mPackages;
-        String mCurrentPassword;
-        String mEncryptPassword;
-        AtomicBoolean mLatchObject;
         File mFilesDir;
         File mManifestFile;
         File mMetadataFile;
-        
+        boolean mIncludeApks;
 
         class FullBackupRunner implements Runnable {
             PackageInfo mPackage;
@@ -2823,326 +2819,17 @@
             }
         }
 
-        PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 
-                boolean includeApks, boolean includeObbs, boolean includeShared,
-                boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
-                boolean doSystem, String[] packages, AtomicBoolean latch) {
-            mOutputFile = fd;
-            mObserver = observer;
-            mIncludeApks = includeApks;
-            mIncludeObbs = includeObbs;
-            mIncludeShared = includeShared;
-            mDoWidgets = doWidgets;
-            mAllApps = doAllApps;
-            mIncludeSystem = doSystem;
-            mPackages = (packages == null)
-                    ? new ArrayList<String>()
-                    : new ArrayList<String>(Arrays.asList(packages));
-            mCurrentPassword = curPassword;
-            // when backing up, if there is a current backup password, we require that
-            // the user use a nonempty encryption password as well.  if one is supplied
-            // in the UI we use that, but if the UI was left empty we fall back to the
-            // current backup password (which was supplied by the user as well).
-            if (encryptPassword == null || "".equals(encryptPassword)) {
-                mEncryptPassword = curPassword;
-            } else {
-                mEncryptPassword = encryptPassword;
-            }
-            mLatchObject = latch;
-
+        FullBackupEngine(OutputStream output, String packageName, boolean alsoApks) {
+            mOutput = output;
+            mIncludeApks = alsoApks;
             mFilesDir = new File("/data/system");
             mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
             mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
         }
 
-        void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
-            for (String pkgName : pkgNames) {
-                if (!set.containsKey(pkgName)) {
-                    try {
-                        PackageInfo info = mPackageManager.getPackageInfo(pkgName,
-                                PackageManager.GET_SIGNATURES);
-                        set.put(pkgName, info);
-                    } catch (NameNotFoundException e) {
-                        Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
-                    }
-                }
-            }
-        }
 
-        @Override
-        public void run() {
-            Slog.i(TAG, "--- Performing full-dataset backup ---");
-
-            TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
-            FullBackupObbConnection obbConnection = new FullBackupObbConnection();
-            obbConnection.establish();  // we'll want this later
-
-            sendStartBackup();
-
-            // doAllApps supersedes the package set if any
-            if (mAllApps) {
-                List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
-                        PackageManager.GET_SIGNATURES);
-                for (int i = 0; i < allPackages.size(); i++) {
-                    PackageInfo pkg = allPackages.get(i);
-                    // Exclude system apps if we've been asked to do so
-                    if (mIncludeSystem == true
-                            || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
-                        packagesToBackup.put(pkg.packageName, pkg);
-                    }
-                }
-            }
-
-            // If we're doing widget state as well, ensure that we have all the involved
-            // host & provider packages in the set
-            if (mDoWidgets) {
-                List<String> pkgs =
-                        AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
-                if (pkgs != null) {
-                    if (MORE_DEBUG) {
-                        Slog.i(TAG, "Adding widget participants to backup set:");
-                        StringBuilder sb = new StringBuilder(128);
-                        sb.append("   ");
-                        for (String s : pkgs) {
-                            sb.append(' ');
-                            sb.append(s);
-                        }
-                        Slog.i(TAG, sb.toString());
-                    }
-                    addPackagesToSet(packagesToBackup, pkgs);
-                }
-            }
-
-            // Now process the command line argument packages, if any. Note that explicitly-
-            // named system-partition packages will be included even if includeSystem was
-            // set to false.
-            if (mPackages != null) {
-                addPackagesToSet(packagesToBackup, mPackages);
-            }
-
-            // Now we cull any inapplicable / inappropriate packages from the set
-            Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
-            while (iter.hasNext()) {
-                PackageInfo pkg = iter.next().getValue();
-                if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
-                        || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
-                    // Cull any packages that have indicated that backups are not permitted, as well
-                    // as any explicit mention of the 'special' shared-storage agent package (we
-                    // handle that one at the end).
-                    iter.remove();
-                } else if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
-                        && (pkg.applicationInfo.backupAgentName == null)) {
-                    // Cull any packages that run as system-domain uids but do not define their
-                    // own backup agents
-                    if (MORE_DEBUG) {
-                        Slog.i(TAG, "... ignoring non-agent system package " + pkg.packageName);
-                    }
-                    iter.remove();
-                }
-            }
-
-            // flatten the set of packages now so we can explicitly control the ordering
-            ArrayList<PackageInfo> backupQueue =
-                    new ArrayList<PackageInfo>(packagesToBackup.values());
-
-            FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
-            OutputStream out = null;
-
-            PackageInfo pkg = null;
-            try {
-                boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
-                boolean compressing = COMPRESS_FULL_BACKUPS;
-                OutputStream finalOutput = ofstream;
-
-                // Verify that the given password matches the currently-active
-                // backup password, if any
-                if (!backupPasswordMatches(mCurrentPassword)) {
-                    if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
-                    return;
-                }
-
-                // Write the global file header.  All strings are UTF-8 encoded; lines end
-                // with a '\n' byte.  Actual backup data begins immediately following the
-                // final '\n'.
-                //
-                // line 1: "ANDROID BACKUP"
-                // line 2: backup file format version, currently "2"
-                // line 3: compressed?  "0" if not compressed, "1" if compressed.
-                // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
-                //
-                // When line 4 is not "none", then additional header data follows:
-                //
-                // line 5: user password salt [hex]
-                // line 6: master key checksum salt [hex]
-                // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
-                // line 8: IV of the user key [hex]
-                // line 9: master key blob [hex]
-                //     IV of the master key, master key itself, master key checksum hash
-                //
-                // The master key checksum is the master key plus its checksum salt, run through
-                // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
-                // correct password for decrypting the archive:  the master key decrypted from
-                // the archive using the user-supplied password is also run through PBKDF2 in
-                // this way, and if the result does not match the checksum as stored in the
-                // archive, then we know that the user-supplied password does not match the
-                // archive's.
-                StringBuilder headerbuf = new StringBuilder(1024);
-
-                headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
-                headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
-                headerbuf.append(compressing ? "\n1\n" : "\n0\n");
-
-                try {
-                    // Set up the encryption stage if appropriate, and emit the correct header
-                    if (encrypting) {
-                        finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
-                    } else {
-                        headerbuf.append("none\n");
-                    }
-
-                    byte[] header = headerbuf.toString().getBytes("UTF-8");
-                    ofstream.write(header);
-
-                    // Set up the compression stage feeding into the encryption stage (if any)
-                    if (compressing) {
-                        Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
-                        finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
-                    }
-
-                    out = finalOutput;
-                } catch (Exception e) {
-                    // Should never happen!
-                    Slog.e(TAG, "Unable to emit archive header", e);
-                    return;
-                }
-
-                // Shared storage if requested
-                if (mIncludeShared) {
-                    try {
-                        pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
-                        backupQueue.add(pkg);
-                    } catch (NameNotFoundException e) {
-                        Slog.e(TAG, "Unable to find shared-storage backup handler");
-                    }
-                }
-
-                // Now back up the app data via the agent mechanism
-                int N = backupQueue.size();
-                for (int i = 0; i < N; i++) {
-                    pkg = backupQueue.get(i);
-                    backupOnePackage(pkg, out);
-
-                    // after the app's agent runs to handle its private filesystem
-                    // contents, back up any OBB content it has on its behalf.
-                    if (mIncludeObbs) {
-                        boolean obbOkay = obbConnection.backupObbs(pkg, out);
-                        if (!obbOkay) {
-                            throw new RuntimeException("Failure writing OBB stack for " + pkg);
-                        }
-                    }
-                }
-
-                // Done!
-                finalizeBackup(out);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "App died during full backup");
-            } catch (Exception e) {
-                Slog.e(TAG, "Internal exception during full backup", e);
-            } finally {
-                tearDown(pkg);
-                try {
-                    if (out != null) out.close();
-                    mOutputFile.close();
-                } catch (IOException e) {
-                    /* nothing we can do about this */
-                }
-                synchronized (mCurrentOpLock) {
-                    mCurrentOperations.clear();
-                }
-                synchronized (mLatchObject) {
-                    mLatchObject.set(true);
-                    mLatchObject.notifyAll();
-                }
-                sendEndBackup();
-                obbConnection.tearDown();
-                if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
-                mWakelock.release();
-            }
-        }
-
-        private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
-                OutputStream ofstream) throws Exception {
-            // User key will be used to encrypt the master key.
-            byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
-            SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
-                    PBKDF2_HASH_ROUNDS);
-
-            // the master key is random for each backup
-            byte[] masterPw = new byte[256 / 8];
-            mRng.nextBytes(masterPw);
-            byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
-
-            // primary encryption of the datastream with the random key
-            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
-            SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
-            c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
-            OutputStream finalOutput = new CipherOutputStream(ofstream, c);
-
-            // line 4: name of encryption algorithm
-            headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
-            headerbuf.append('\n');
-            // line 5: user password salt [hex]
-            headerbuf.append(byteArrayToHex(newUserSalt));
-            headerbuf.append('\n');
-            // line 6: master key checksum salt [hex]
-            headerbuf.append(byteArrayToHex(checksumSalt));
-            headerbuf.append('\n');
-            // line 7: number of PBKDF2 rounds used [decimal]
-            headerbuf.append(PBKDF2_HASH_ROUNDS);
-            headerbuf.append('\n');
-
-            // line 8: IV of the user key [hex]
-            Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
-            mkC.init(Cipher.ENCRYPT_MODE, userKey);
-
-            byte[] IV = mkC.getIV();
-            headerbuf.append(byteArrayToHex(IV));
-            headerbuf.append('\n');
-
-            // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
-            //    [byte] IV length = Niv
-            //    [array of Niv bytes] IV itself
-            //    [byte] master key length = Nmk
-            //    [array of Nmk bytes] master key itself
-            //    [byte] MK checksum hash length = Nck
-            //    [array of Nck bytes] master key checksum hash
-            //
-            // The checksum is the (master key + checksum salt), run through the
-            // stated number of PBKDF2 rounds
-            IV = c.getIV();
-            byte[] mk = masterKeySpec.getEncoded();
-            byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
-                    checksumSalt, PBKDF2_HASH_ROUNDS);
-
-            ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
-                    + checksum.length + 3);
-            DataOutputStream mkOut = new DataOutputStream(blob);
-            mkOut.writeByte(IV.length);
-            mkOut.write(IV);
-            mkOut.writeByte(mk.length);
-            mkOut.write(mk);
-            mkOut.writeByte(checksum.length);
-            mkOut.write(checksum);
-            mkOut.flush();
-            byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
-            headerbuf.append(byteArrayToHex(encryptedMk));
-            headerbuf.append('\n');
-
-            return finalOutput;
-        }
-
-        private void backupOnePackage(PackageInfo pkg, OutputStream out)
-                throws RemoteException {
+        public int backupOnePackage(PackageInfo pkg) throws RemoteException {
+            int result = BackupTransport.TRANSPORT_OK;
             Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
 
             IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
@@ -3162,47 +2849,52 @@
 
                     byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
                             UserHandle.USER_OWNER);
-                    sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
 
                     final int token = generateToken();
                     FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
                             token, sendApk, !isSharedStorage, widgetBlob);
                     pipes[1].close();   // the runner has dup'd it
                     pipes[1] = null;
-                    Thread t = new Thread(runner);
+                    Thread t = new Thread(runner, "app-data-runner");
                     t.start();
 
-                    // Now pull data from the app and stuff it into the compressor
+                    // Now pull data from the app and stuff it into the output
                     try {
-                        routeSocketDataToOutput(pipes[0], out);
+                        routeSocketDataToOutput(pipes[0], mOutput);
                     } catch (IOException e) {
                         Slog.i(TAG, "Caught exception reading from agent", e);
+                        result = BackupTransport.AGENT_ERROR;
                     }
 
                     if (!waitUntilOperationComplete(token)) {
                         Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
+                        result = BackupTransport.AGENT_ERROR;
                     } else {
                         if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
                     }
 
                 } catch (IOException e) {
                     Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+                    result = BackupTransport.AGENT_ERROR;
                 } finally {
                     try {
                         // flush after every package
-                        out.flush();
+                        mOutput.flush();
                         if (pipes != null) {
                             if (pipes[0] != null) pipes[0].close();
                             if (pipes[1] != null) pipes[1].close();
                         }
                     } catch (IOException e) {
                         Slog.w(TAG, "Error bringing down backup stack");
+                        result = BackupTransport.TRANSPORT_ERROR;
                     }
                 }
             } else {
                 Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
+                result = BackupTransport.AGENT_ERROR;
             }
             tearDown(pkg);
+            return result;
         }
 
         private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
@@ -3232,16 +2924,6 @@
             }
         }
 
-        private void finalizeBackup(OutputStream out) {
-            try {
-                // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
-                byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
-                out.write(eof);
-            } catch (IOException e) {
-                Slog.w(TAG, "Error attempting to finalize backup stream");
-            }
-        }
-
         private void writeAppManifest(PackageInfo pkg, File manifestFile,
                 boolean withApk, boolean withWidgets) throws IOException {
             // Manifest format. All data are strings ending in LF:
@@ -3332,7 +3014,7 @@
                             if (MORE_DEBUG) Slog.d(TAG, "Backup complete, killing host process");
                             mActivityManager.killApplicationProcess(app.processName, app.uid);
                         } else {
-                            if (MORE_DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
+                            if (MORE_DEBUG) Slog.d(TAG, "Not killing after backup: " + app.processName);
                         }
                     } catch (RemoteException e) {
                         Slog.d(TAG, "Lost app trying to shut down");
@@ -3340,9 +3022,18 @@
                 }
             }
         }
+    }
+
+    // Generic driver skeleton for full backup operations
+    abstract class FullBackupTask implements Runnable {
+        IFullBackupRestoreObserver mObserver;
+
+        FullBackupTask(IFullBackupRestoreObserver observer) {
+            mObserver = observer;
+        }
 
         // wrappers for observer use
-        void sendStartBackup() {
+        final void sendStartBackup() {
             if (mObserver != null) {
                 try {
                     mObserver.onStartBackup();
@@ -3353,7 +3044,7 @@
             }
         }
 
-        void sendOnBackupPackage(String name) {
+        final void sendOnBackupPackage(String name) {
             if (mObserver != null) {
                 try {
                     // TODO: use a more user-friendly name string
@@ -3365,7 +3056,7 @@
             }
         }
 
-        void sendEndBackup() {
+        final void sendEndBackup() {
             if (mObserver != null) {
                 try {
                     mObserver.onEndBackup();
@@ -3377,6 +3068,556 @@
         }
     }
 
+    // Full backup task variant used for adb backup
+    class PerformAdbBackupTask extends FullBackupTask {
+        FullBackupEngine mBackupEngine;
+        final AtomicBoolean mLatch;
+
+        ParcelFileDescriptor mOutputFile;
+        DeflaterOutputStream mDeflater;
+        boolean mIncludeApks;
+        boolean mIncludeObbs;
+        boolean mIncludeShared;
+        boolean mDoWidgets;
+        boolean mAllApps;
+        boolean mIncludeSystem;
+        boolean mCompress;
+        ArrayList<String> mPackages;
+        String mCurrentPassword;
+        String mEncryptPassword;
+        
+        PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 
+                boolean includeApks, boolean includeObbs, boolean includeShared,
+                boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
+                boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) {
+            super(observer);
+            mLatch = latch;
+
+            mOutputFile = fd;
+            mIncludeApks = includeApks;
+            mIncludeObbs = includeObbs;
+            mIncludeShared = includeShared;
+            mDoWidgets = doWidgets;
+            mAllApps = doAllApps;
+            mIncludeSystem = doSystem;
+            mPackages = (packages == null)
+                    ? new ArrayList<String>()
+                    : new ArrayList<String>(Arrays.asList(packages));
+            mCurrentPassword = curPassword;
+            // when backing up, if there is a current backup password, we require that
+            // the user use a nonempty encryption password as well.  if one is supplied
+            // in the UI we use that, but if the UI was left empty we fall back to the
+            // current backup password (which was supplied by the user as well).
+            if (encryptPassword == null || "".equals(encryptPassword)) {
+                mEncryptPassword = curPassword;
+            } else {
+                mEncryptPassword = encryptPassword;
+            }
+            mCompress = doCompress;
+        }
+
+        void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
+            for (String pkgName : pkgNames) {
+                if (!set.containsKey(pkgName)) {
+                    try {
+                        PackageInfo info = mPackageManager.getPackageInfo(pkgName,
+                                PackageManager.GET_SIGNATURES);
+                        set.put(pkgName, info);
+                    } catch (NameNotFoundException e) {
+                        Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
+                    }
+                }
+            }
+        }
+
+        private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
+                OutputStream ofstream) throws Exception {
+            // User key will be used to encrypt the master key.
+            byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
+            SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
+                    PBKDF2_HASH_ROUNDS);
+
+            // the master key is random for each backup
+            byte[] masterPw = new byte[256 / 8];
+            mRng.nextBytes(masterPw);
+            byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
+
+            // primary encryption of the datastream with the random key
+            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
+            c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
+            OutputStream finalOutput = new CipherOutputStream(ofstream, c);
+
+            // line 4: name of encryption algorithm
+            headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
+            headerbuf.append('\n');
+            // line 5: user password salt [hex]
+            headerbuf.append(byteArrayToHex(newUserSalt));
+            headerbuf.append('\n');
+            // line 6: master key checksum salt [hex]
+            headerbuf.append(byteArrayToHex(checksumSalt));
+            headerbuf.append('\n');
+            // line 7: number of PBKDF2 rounds used [decimal]
+            headerbuf.append(PBKDF2_HASH_ROUNDS);
+            headerbuf.append('\n');
+
+            // line 8: IV of the user key [hex]
+            Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            mkC.init(Cipher.ENCRYPT_MODE, userKey);
+
+            byte[] IV = mkC.getIV();
+            headerbuf.append(byteArrayToHex(IV));
+            headerbuf.append('\n');
+
+            // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
+            //    [byte] IV length = Niv
+            //    [array of Niv bytes] IV itself
+            //    [byte] master key length = Nmk
+            //    [array of Nmk bytes] master key itself
+            //    [byte] MK checksum hash length = Nck
+            //    [array of Nck bytes] master key checksum hash
+            //
+            // The checksum is the (master key + checksum salt), run through the
+            // stated number of PBKDF2 rounds
+            IV = c.getIV();
+            byte[] mk = masterKeySpec.getEncoded();
+            byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
+                    checksumSalt, PBKDF2_HASH_ROUNDS);
+
+            ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
+                    + checksum.length + 3);
+            DataOutputStream mkOut = new DataOutputStream(blob);
+            mkOut.writeByte(IV.length);
+            mkOut.write(IV);
+            mkOut.writeByte(mk.length);
+            mkOut.write(mk);
+            mkOut.writeByte(checksum.length);
+            mkOut.write(checksum);
+            mkOut.flush();
+            byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
+            headerbuf.append(byteArrayToHex(encryptedMk));
+            headerbuf.append('\n');
+
+            return finalOutput;
+        }
+
+        private void finalizeBackup(OutputStream out) {
+            try {
+                // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
+                byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
+                out.write(eof);
+            } catch (IOException e) {
+                Slog.w(TAG, "Error attempting to finalize backup stream");
+            }
+        }
+
+        @Override
+        public void run() {
+            Slog.i(TAG, "--- Performing full-dataset adb backup ---");
+
+            TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
+            FullBackupObbConnection obbConnection = new FullBackupObbConnection();
+            obbConnection.establish();  // we'll want this later
+
+            sendStartBackup();
+
+            // doAllApps supersedes the package set if any
+            if (mAllApps) {
+                List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
+                        PackageManager.GET_SIGNATURES);
+                for (int i = 0; i < allPackages.size(); i++) {
+                    PackageInfo pkg = allPackages.get(i);
+                    // Exclude system apps if we've been asked to do so
+                    if (mIncludeSystem == true
+                            || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+                        packagesToBackup.put(pkg.packageName, pkg);
+                    }
+                }
+            }
+
+            // If we're doing widget state as well, ensure that we have all the involved
+            // host & provider packages in the set
+            if (mDoWidgets) {
+                List<String> pkgs =
+                        AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
+                if (pkgs != null) {
+                    if (MORE_DEBUG) {
+                        Slog.i(TAG, "Adding widget participants to backup set:");
+                        StringBuilder sb = new StringBuilder(128);
+                        sb.append("   ");
+                        for (String s : pkgs) {
+                            sb.append(' ');
+                            sb.append(s);
+                        }
+                        Slog.i(TAG, sb.toString());
+                    }
+                    addPackagesToSet(packagesToBackup, pkgs);
+                }
+            }
+
+            // Now process the command line argument packages, if any. Note that explicitly-
+            // named system-partition packages will be included even if includeSystem was
+            // set to false.
+            if (mPackages != null) {
+                addPackagesToSet(packagesToBackup, mPackages);
+            }
+
+            // Now we cull any inapplicable / inappropriate packages from the set
+            Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
+            while (iter.hasNext()) {
+                PackageInfo pkg = iter.next().getValue();
+                if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
+                        || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
+                    // Cull any packages that have indicated that backups are not permitted, as well
+                    // as any explicit mention of the 'special' shared-storage agent package (we
+                    // handle that one at the end).
+                    iter.remove();
+                } else if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
+                        && (pkg.applicationInfo.backupAgentName == null)) {
+                    // Cull any packages that run as system-domain uids but do not define their
+                    // own backup agents
+                    if (MORE_DEBUG) {
+                        Slog.i(TAG, "... ignoring non-agent system package " + pkg.packageName);
+                    }
+                    iter.remove();
+                }
+            }
+
+            // flatten the set of packages now so we can explicitly control the ordering
+            ArrayList<PackageInfo> backupQueue =
+                    new ArrayList<PackageInfo>(packagesToBackup.values());
+            FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
+            OutputStream out = null;
+
+            PackageInfo pkg = null;
+            try {
+                boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
+                OutputStream finalOutput = ofstream;
+
+                // Verify that the given password matches the currently-active
+                // backup password, if any
+                if (!backupPasswordMatches(mCurrentPassword)) {
+                    if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+                    return;
+                }
+
+                // Write the global file header.  All strings are UTF-8 encoded; lines end
+                // with a '\n' byte.  Actual backup data begins immediately following the
+                // final '\n'.
+                //
+                // line 1: "ANDROID BACKUP"
+                // line 2: backup file format version, currently "2"
+                // line 3: compressed?  "0" if not compressed, "1" if compressed.
+                // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
+                //
+                // When line 4 is not "none", then additional header data follows:
+                //
+                // line 5: user password salt [hex]
+                // line 6: master key checksum salt [hex]
+                // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
+                // line 8: IV of the user key [hex]
+                // line 9: master key blob [hex]
+                //     IV of the master key, master key itself, master key checksum hash
+                //
+                // The master key checksum is the master key plus its checksum salt, run through
+                // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
+                // correct password for decrypting the archive:  the master key decrypted from
+                // the archive using the user-supplied password is also run through PBKDF2 in
+                // this way, and if the result does not match the checksum as stored in the
+                // archive, then we know that the user-supplied password does not match the
+                // archive's.
+                StringBuilder headerbuf = new StringBuilder(1024);
+
+                headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
+                headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
+                headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
+
+                try {
+                    // Set up the encryption stage if appropriate, and emit the correct header
+                    if (encrypting) {
+                        finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
+                    } else {
+                        headerbuf.append("none\n");
+                    }
+
+                    byte[] header = headerbuf.toString().getBytes("UTF-8");
+                    ofstream.write(header);
+
+                    // Set up the compression stage feeding into the encryption stage (if any)
+                    if (mCompress) {
+                        Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
+                        finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
+                    }
+
+                    out = finalOutput;
+                } catch (Exception e) {
+                    // Should never happen!
+                    Slog.e(TAG, "Unable to emit archive header", e);
+                    return;
+                }
+
+                // Shared storage if requested
+                if (mIncludeShared) {
+                    try {
+                        pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
+                        backupQueue.add(pkg);
+                    } catch (NameNotFoundException e) {
+                        Slog.e(TAG, "Unable to find shared-storage backup handler");
+                    }
+                }
+
+                // Now actually run the constructed backup sequence
+                int N = backupQueue.size();
+                for (int i = 0; i < N; i++) {
+                    pkg = backupQueue.get(i);
+                    final boolean isSharedStorage =
+                            pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
+
+                    mBackupEngine = new FullBackupEngine(out, pkg.packageName, mIncludeApks);
+                    sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
+                    mBackupEngine.backupOnePackage(pkg);
+
+                    // after the app's agent runs to handle its private filesystem
+                    // contents, back up any OBB content it has on its behalf.
+                    if (mIncludeObbs) {
+                        boolean obbOkay = obbConnection.backupObbs(pkg, out);
+                        if (!obbOkay) {
+                            throw new RuntimeException("Failure writing OBB stack for " + pkg);
+                        }
+                    }
+                }
+
+                // Done!
+                finalizeBackup(out);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "App died during full backup");
+            } catch (Exception e) {
+                Slog.e(TAG, "Internal exception during full backup", e);
+            } finally {
+                try {
+                    if (out != null) out.close();
+                    mOutputFile.close();
+                } catch (IOException e) {
+                    /* nothing we can do about this */
+                }
+                synchronized (mCurrentOpLock) {
+                    mCurrentOperations.clear();
+                }
+                synchronized (mLatch) {
+                    mLatch.set(true);
+                    mLatch.notifyAll();
+                }
+                sendEndBackup();
+                obbConnection.tearDown();
+                if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
+                mWakelock.release();
+            }
+        }
+    }
+
+    // Full backup task extension used for transport-oriented operation
+    class PerformFullTransportBackupTask extends FullBackupTask {
+        static final String TAG = "PFTBT";
+        ArrayList<PackageInfo> mPackages;
+        AtomicBoolean mLatch;
+
+        PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, 
+                String[] whichPackages, AtomicBoolean latch) {
+            super(observer);
+            mLatch = latch;
+            mPackages = new ArrayList<PackageInfo>(whichPackages.length);
+
+            for (String pkg : whichPackages) {
+                try {
+                    PackageInfo info = mPackageManager.getPackageInfo(pkg,
+                            PackageManager.GET_SIGNATURES);
+                    if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
+                            || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
+                        // Cull any packages that have indicated that backups are not permitted,
+                        // as well as any explicit mention of the 'special' shared-storage agent
+                        // package (we handle that one at the end).
+                        if (MORE_DEBUG) {
+                            Slog.d(TAG, "Ignoring opted-out package " + pkg);
+                        }
+                        continue;
+                    } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
+                            && (info.applicationInfo.backupAgentName == null)) {
+                        // Cull any packages that run as system-domain uids but do not define their
+                        // own backup agents
+                        if (MORE_DEBUG) {
+                            Slog.d(TAG, "Ignoring non-agent system package " + pkg);
+                        }
+                        continue;
+                    }
+                    mPackages.add(info);
+                } catch (NameNotFoundException e) {
+                    Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            IBackupTransport transport = getTransport(mCurrentTransport);
+            if (transport == null) {
+                Slog.w(TAG, "Transport not present; full data backup not performed");
+                return;
+            }
+
+            // data from the app, passed to us for bridging to the transport
+            ParcelFileDescriptor[] enginePipes = null;
+
+            // Pipe through which we write data to the transport
+            ParcelFileDescriptor[] transportPipes = null;
+
+            try {
+                // Set up to send data to the transport
+                if (transport != null) {
+                    for (PackageInfo target : mPackages) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Initiating full-data transport backup of "
+                                    + target.packageName);
+                        }
+                        transportPipes = ParcelFileDescriptor.createPipe();
+
+                        // Tell the transport the data's coming
+                        int result = transport.performFullBackup(target, transportPipes[0]);
+                        if (result == BackupTransport.TRANSPORT_OK) {
+                            // The transport has its own copy of the read end of the pipe,
+                            // so close ours now
+                            transportPipes[0].close();
+                            transportPipes[0] = null;
+
+                            // Now set up the backup engine / data source end of things
+                            enginePipes = ParcelFileDescriptor.createPipe();
+                            AtomicBoolean runnerLatch = new AtomicBoolean(false);
+                            SinglePackageBackupRunner backupRunner =
+                                    new SinglePackageBackupRunner(enginePipes[1], target,
+                                            runnerLatch);
+                            // The runner dup'd the pipe half, so we close it here
+                            enginePipes[1].close();
+                            enginePipes[1] = null;
+
+                            // Spin off the runner to fetch the app's data and pipe it
+                            // into the engine pipes
+                            (new Thread(backupRunner, "package-backup-bridge")).start();
+
+                            // Read data off the engine pipe and pass it to the transport
+                            // pipe until we hit EOD on the input stream.
+                            FileInputStream in = new FileInputStream(
+                                    enginePipes[0].getFileDescriptor());
+                            FileOutputStream out = new FileOutputStream(
+                                    transportPipes[1].getFileDescriptor());
+                            byte[] buffer = new byte[8192];
+                            int nRead = 0;
+                            do {
+                                nRead = in.read(buffer);
+                                if (nRead > 0) {
+                                    out.write(buffer, 0, nRead);
+                                    result = transport.sendBackupData(nRead);
+                                }
+                            } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
+
+                            // Done -- how did it turn out?
+                            if (result == BackupTransport.TRANSPORT_OK){
+                                result = transport.finishBackup();
+                            } else {
+                                Slog.w(TAG, "Error backing up " + target.packageName);
+                            }
+                        } else if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+                            if (DEBUG) {
+                                Slog.i(TAG, "Transport rejected backup of " + target.packageName
+                                        + ", skipping");
+                            }
+                            // do nothing, clean up, and continue looping
+                        } else {
+                            if (DEBUG) {
+                                Slog.i(TAG, "Transport failed; aborting backup");
+                                return;
+                            }
+                        }
+                        cleanUpPipes(transportPipes);
+                        cleanUpPipes(enginePipes);
+                    }
+
+                    if (DEBUG) {
+                        Slog.i(TAG, "Full backup completed.");
+                    }
+                }
+            } catch (Exception e) {
+                Slog.w(TAG, "Exception trying full transport backup", e);
+            } finally {
+                cleanUpPipes(transportPipes);
+                cleanUpPipes(enginePipes);
+                synchronized (mLatch) {
+                    mLatch.set(true);
+                    mLatch.notifyAll();
+                }
+            }
+        }
+
+        void cleanUpPipes(ParcelFileDescriptor[] pipes) {
+            if (pipes != null) {
+                if (pipes[0] != null) {
+                    ParcelFileDescriptor fd = pipes[0];
+                    pipes[0] = null;
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Unable to close pipe!");
+                    }
+                }
+                if (pipes[1] != null) {
+                    ParcelFileDescriptor fd = pipes[1];
+                    pipes[1] = null;
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Unable to close pipe!");
+                    }
+                }
+            }
+        }
+
+        // Run the backup and pipe it back to the given socket -- expects to run on
+        // a standalone thread.  The  runner owns this half of the pipe, and closes
+        // it to indicate EOD to the other end.
+        class SinglePackageBackupRunner implements Runnable {
+            final ParcelFileDescriptor mOutput;
+            final PackageInfo mTarget;
+            final AtomicBoolean mLatch;
+
+            SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
+                    AtomicBoolean latch) throws IOException {
+                int oldfd = output.getFd();
+                mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
+                mTarget = target;
+                mLatch = latch;
+            }
+
+            @Override
+            public void run() {
+                try {
+                    FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
+                    FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName, false);
+                    engine.backupOnePackage(mTarget);
+                } catch (Exception e) {
+                    Slog.e(TAG, "Exception during full package backup of " + mTarget);
+                } finally {
+                    synchronized (mLatch) {
+                        mLatch.set(true);
+                        mLatch.notifyAll();
+                    }
+                    try {
+                        mOutput.close();
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Error closing transport pipe in runner");
+                    }
+                }
+            }
+            
+        }
+    }
 
     // ----- Full restore from a file/socket -----
 
@@ -3410,7 +3651,7 @@
         ACCEPT_IF_APK
     }
 
-    class PerformFullRestoreTask extends ObbServiceClient implements Runnable {
+    class PerformFullRestoreTask implements Runnable {
         ParcelFileDescriptor mInputFile;
         String mCurrentPassword;
         String mDecryptPassword;
@@ -3877,7 +4118,7 @@
                                         Slog.d(TAG, "system process agent - spinning a thread");
                                         RestoreFileRunnable runner = new RestoreFileRunnable(
                                                 mAgent, info, mPipes[0], token);
-                                        new Thread(runner).start();
+                                        new Thread(runner, "restore-sys-runner").start();
                                     } else {
                                         mAgent.doRestoreFile(mPipes[0], info.size, info.type,
                                                 info.domain, info.path, info.mode, info.mtime,
@@ -4937,7 +5178,9 @@
 
         void restorePmMetadata() {
             try {
-                String packageName = mTransport.nextRestorePackage();
+                RestoreDescription desc = mTransport.nextRestorePackage();
+                // TODO: handle full-data stream restore payloads
+                String packageName = desc.getPackageName();
                 if (packageName == null) {
                     Slog.e(TAG, "Error getting first restore package");
                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
@@ -5005,7 +5248,9 @@
 
         void restoreNextAgent() {
             try {
-                String packageName = mTransport.nextRestorePackage();
+                final RestoreDescription desc = mTransport.nextRestorePackage();
+                // TODO: handle full-data stream restore payloads
+                String packageName = desc.getPackageName();
 
                 if (packageName == null) {
                     Slog.e(TAG, "Error getting next restore package");
@@ -5684,13 +5929,16 @@
         return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
     }
 
-    // Run a *full* backup pass for the given package, writing the resulting data stream
+    // Run a *full* backup pass for the given packages, writing the resulting data stream
     // to the supplied file descriptor.  This method is synchronous and does not return
     // to the caller until the backup has been completed.
+    //
+    // This is the variant used by 'adb backup'; it requires on-screen confirmation
+    // by the user because it can be used to offload data over untrusted USB.
     @Override
     public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
             boolean includeObbs, boolean includeShared, boolean doWidgets,
-            boolean doAllApps, boolean includeSystem, String[] pkgList) {
+            boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
 
         final int callingUserHandle = UserHandle.getCallingUserId();
@@ -5725,7 +5973,7 @@
             Slog.i(TAG, "Beginning full backup...");
 
             FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
-                    includeShared, doWidgets, doAllApps, includeSystem, pkgList);
+                    includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList);
             final int token = generateToken();
             synchronized (mFullConfirmations) {
                 mFullConfirmations.put(token, params);
@@ -5759,6 +6007,36 @@
         }
     }
 
+    @Override
+    public void fullTransportBackup(String[] pkgNames) {
+        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+                "fullTransportBackup");
+
+        final int callingUserHandle = UserHandle.getCallingUserId();
+        if (callingUserHandle != UserHandle.USER_OWNER) {
+            throw new IllegalStateException("Restore supported only for the device owner");
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG, "fullTransportBackup()");
+        }
+
+        AtomicBoolean latch = new AtomicBoolean(false);
+        PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames, latch);
+        (new Thread(task, "full-transport-master")).start();
+        synchronized (latch) {
+            try {
+                while (latch.get() == false) {
+                    latch.wait();
+                }
+            } catch (InterruptedException e) {}
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "Done with full transport backup.");
+        }
+    }
+
+    @Override
     public void fullRestore(ParcelFileDescriptor fd) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
 
@@ -5876,8 +6154,8 @@
 
                     if (allow) {
                         final int verb = params instanceof FullBackupParams
-                                ? MSG_RUN_FULL_BACKUP
-                                : MSG_RUN_FULL_RESTORE;
+                                ? MSG_RUN_ADB_BACKUP
+                                : MSG_RUN_ADB_RESTORE;
 
                         params.observer = observer;
                         params.curPassword = curPassword;
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index fe5c2ef..aeb195f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.database.ContentObserver;
 import android.os.BatteryStats;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.am.BatteryStatsService;
@@ -149,8 +150,8 @@
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
         mLowBatteryWarningLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
+        mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
         mShutdownBatteryTemperature = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shutdownBatteryTemperature);
 
@@ -173,11 +174,39 @@
     void systemReady() {
         // check our power situation now that it is safe to display the shutdown dialog.
         synchronized (mLock) {
-            shutdownIfNoPowerLocked();
-            shutdownIfOverTempLocked();
+            ContentObserver obs = new ContentObserver(mHandler) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    synchronized (mLock) {
+                        updateBatteryWarningLevelLocked();
+                    }
+                }
+            };
+            final ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+                    false, obs, UserHandle.USER_ALL);
+            updateBatteryWarningLevelLocked();
         }
     }
 
+    void updateBatteryWarningLevelLocked() {
+        final ContentResolver resolver = mContext.getContentResolver();
+        int defWarnLevel = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lowBatteryWarningLevel);
+        mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+        if (mLowBatteryWarningLevel == 0) {
+            mLowBatteryWarningLevel = defWarnLevel;
+        }
+        if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
+            mLowBatteryWarningLevel = mCriticalBatteryLevel;
+        }
+        mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
+        processValuesLocked(true);
+    }
+
     /**
      * Returns true if the device is plugged into any of the specified plug types.
      */
@@ -232,7 +261,7 @@
         }
     }
 
-    public boolean isBatteryLowLocked() {
+    public boolean shouldSendBatteryLowLocked() {
         final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
         final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
 
@@ -299,14 +328,14 @@
             if (!mUpdatesStopped) {
                 mBatteryProps = props;
                 // Process the new values.
-                processValuesLocked();
+                processValuesLocked(false);
             } else {
                 mLastBatteryProps.set(props);
             }
         }
     }
 
-    private void processValuesLocked() {
+    private void processValuesLocked(boolean force) {
         boolean logOutlier = false;
         long dischargeDuration = 0;
 
@@ -349,14 +378,14 @@
         shutdownIfNoPowerLocked();
         shutdownIfOverTempLocked();
 
-        if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+        if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
                 mBatteryProps.batteryHealth != mLastBatteryHealth ||
                 mBatteryProps.batteryPresent != mLastBatteryPresent ||
                 mBatteryProps.batteryLevel != mLastBatteryLevel ||
                 mPlugType != mLastPlugType ||
                 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
                 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
-                mInvalidCharger != mLastInvalidCharger) {
+                mInvalidCharger != mLastInvalidCharger)) {
 
             if (mPlugType != mLastPlugType) {
                 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -400,7 +429,24 @@
                 logOutlier = true;
             }
 
-            mBatteryLevelLow = isBatteryLowLocked();
+            if (!mBatteryLevelLow) {
+                // Should we now switch in to low battery mode?
+                if (mPlugType == BATTERY_PLUGGED_NONE
+                        && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
+                    mBatteryLevelLow = true;
+                }
+            } else {
+                // Should we now switch out of low battery mode?
+                if (mPlugType != BATTERY_PLUGGED_NONE) {
+                    mBatteryLevelLow = false;
+                } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel)  {
+                    mBatteryLevelLow = false;
+                } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
+                    // If being forced, the previous state doesn't matter, we will just
+                    // absolutely check to see if we are now above the warning level.
+                    mBatteryLevelLow = false;
+                }
+            }
 
             sendIntentLocked();
 
@@ -428,7 +474,7 @@
                 });
             }
 
-            if (mBatteryLevelLow) {
+            if (shouldSendBatteryLowLocked()) {
                 mSentLowBatteryBroadcast = true;
                 mHandler.post(new Runnable() {
                     @Override
@@ -650,7 +696,7 @@
                         long ident = Binder.clearCallingIdentity();
                         try {
                             mUpdatesStopped = true;
-                            processValuesLocked();
+                            processValuesLocked(false);
                         } finally {
                             Binder.restoreCallingIdentity(ident);
                         }
@@ -664,7 +710,7 @@
                     if (mUpdatesStopped) {
                         mUpdatesStopped = false;
                         mBatteryProps.set(mLastBatteryProps);
-                        processValuesLocked();
+                        processValuesLocked(false);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index e2a8ca2..07c9048 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -308,6 +308,10 @@
     }
 
     public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
+        if (callback == null) {
+            Log.w(TAG, "Callback is null in registerAdapter");
+            return null;
+        }
         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
         msg.obj = callback;
         mHandler.sendMessage(msg);
@@ -317,6 +321,10 @@
     }
 
     public void unregisterAdapter(IBluetoothManagerCallback callback) {
+        if (callback == null) {
+            Log.w(TAG, "Callback is null in unregisterAdapter");
+            return;
+        }
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
                                                 "Need BLUETOOTH permission");
         Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9087726..00bda06 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,7 +20,6 @@
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.NetworkCallbackListener;
 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
 import static android.net.ConnectivityManager.TYPE_DUMMY;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -630,8 +629,8 @@
         if (DBG) log("ConnectivityService starting up");
 
         NetworkCapabilities netCap = new NetworkCapabilities();
-        netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
                 NetworkRequestInfo.REQUEST);
@@ -5410,7 +5409,7 @@
 
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
-            Messenger messenger, int timeoutSec, IBinder binder, int legacyType) {
+            Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
         if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                 == false) {
             enforceConnectivityInternalPermission();
@@ -5418,7 +5417,7 @@
             enforceChangePermission();
         }
 
-        if (timeoutSec < 0 || timeoutSec > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_SEC) {
+        if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
             throw new IllegalArgumentException("Bad timeout specified");
         }
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
@@ -5428,9 +5427,9 @@
                 NetworkRequestInfo.REQUEST);
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
-        if (timeoutSec > 0) {
+        if (timeoutMs > 0) {
             mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
-                    nri), timeoutSec * 1000);
+                    nri), timeoutMs);
         }
         return networkRequest;
     }
@@ -5694,7 +5693,7 @@
         int a2 = 0;
         switch (notificationType) {
             case ConnectivityManager.CALLBACK_LOSING:
-                a1 = 30; // TODO - read this from NetworkMonitor
+                a1 = 30 * 1000; // TODO - read this from NetworkMonitor
                 // fall through
             case ConnectivityManager.CALLBACK_PRECHECK:
             case ConnectivityManager.CALLBACK_AVAILABLE:
diff --git a/services/core/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
deleted file mode 100644
index acc6abe..0000000
--- a/services/core/java/com/android/server/IdleMaintenanceService.java
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.maintenance.IIdleCallback;
-import android.app.maintenance.IIdleService;
-import android.app.maintenance.IdleService;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.WorkSource;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * This service observes the device state and when applicable sends
- * broadcasts at the beginning and at the end of a period during which
- * observers can perform idle maintenance tasks. Typical use of the
- * idle maintenance is to perform somehow expensive tasks that can be
- * postponed to a moment when they will not degrade user experience.
- *
- * The current implementation is very simple. The start of a maintenance
- * window is announced if: the screen is off or showing a dream AND the
- * battery level is more than twenty percent AND at least one hour passed
- * activity).
- *
- * The end of a maintenance window is announced only if: a start was
- * announced AND the screen turned on or a dream was stopped.
- *
- * Method naming note:
- * Methods whose name ends with "Tm" must only be called from the main thread.
- */
-public class IdleMaintenanceService extends BroadcastReceiver {
-
-    private static final boolean DEBUG = false;
-
-    private static final String TAG = IdleMaintenanceService.class.getSimpleName();
-
-    private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
-
-    private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day
-
-    private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent
-
-    private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent
-
-    private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent
-
-    private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min
-
-    private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min
-
-    private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
-        "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
-
-    private static final String ACTION_FORCE_IDLE_MAINTENANCE =
-        "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
-
-    static final int MSG_OP_COMPLETE = 1;
-    static final int MSG_IDLE_FINISHED = 2;
-    static final int MSG_TIMEOUT = 3;
-
-    // when a timeout happened, what were we expecting?
-    static final int VERB_BINDING = 1;
-    static final int VERB_IDLING = 2;
-    static final int VERB_ENDING = 3;
-
-    // What are our relevant timeouts / allocated slices?
-    static final long OP_TIMEOUT = 8 * 1000;  // 8 seconds to bind or ack the start
-    static final long IDLE_TIMESLICE = 10 * 60 * 1000;  // ten minutes for each idler
-
-    private final AlarmManager mAlarmService;
-    private final BatteryService mBatteryService;
-    private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent;
-    private final Context mContext;
-    private final WakeLock mWakeLock;
-    private final WorkSource mSystemWorkSource = new WorkSource(Process.myUid());
-
-    private long mLastIdleMaintenanceStartTimeMillis;
-    private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
-    private boolean mIdleMaintenanceStarted;
-
-    final IdleCallback mCallback;
-    final Handler mHandler;
-
-    final Random mTokenGenerator = new Random();
-
-    int makeToken() {
-        int token;
-        do  {
-            token = mTokenGenerator.nextInt(Integer.MAX_VALUE);
-        } while (token == 0);
-        return token;
-    }
-
-    class ActiveTask {
-        public IdleServiceInfo who;
-        public int verb;
-        public int token;
-
-        ActiveTask(IdleServiceInfo target, int action) {
-            who = target;
-            verb = action;
-            token = makeToken();
-        }
-
-        @Override
-        public String toString() {
-            return "ActiveTask{" + Integer.toHexString(this.hashCode())
-                    + " : verb=" + verb
-                    + " : token=" + token
-                    + " : "+ who + "}";
-        }
-    }
-
-    // What operations are in flight?
-    final SparseArray<ActiveTask> mPendingOperations = new SparseArray<ActiveTask>();
-
-    // Idle service queue management
-    class IdleServiceInfo {
-        public final ComponentName componentName;
-        public final int uid;
-        public IIdleService service;
-
-        IdleServiceInfo(ResolveInfo info, ComponentName cname) {
-            componentName = cname;  // derived from 'info' but this avoids an extra object
-            uid = info.serviceInfo.applicationInfo.uid;
-            service = null;
-        }
-
-        @Override
-        public int hashCode() {
-            return componentName.hashCode();
-        }
-
-        @Override
-        public String toString() {
-            return "IdleServiceInfo{" + componentName
-                    + " / " + (service == null ? "null" : service.asBinder()) + "}";
-        }
-    }
-
-    final ArrayMap<ComponentName, IdleServiceInfo> mIdleServices =
-            new ArrayMap<ComponentName, IdleServiceInfo>();
-    final LinkedList<IdleServiceInfo> mIdleServiceQueue = new LinkedList<IdleServiceInfo>();
-    IdleServiceInfo mCurrentIdler;  // set when we've committed to launching an idler
-    IdleServiceInfo mLastIdler;     // end of queue when idling begins
-
-    void reportNoTimeout(int token, boolean result) {
-        final Message msg = mHandler.obtainMessage(MSG_OP_COMPLETE, result ? 1 : 0, token);
-        mHandler.sendMessage(msg);
-    }
-
-    // Binder acknowledgment trampoline
-    class IdleCallback extends IIdleCallback.Stub {
-        @Override
-        public void acknowledgeStart(int token, boolean result) throws RemoteException {
-            reportNoTimeout(token, result);
-        }
-
-        @Override
-        public void acknowledgeStop(int token) throws RemoteException {
-            reportNoTimeout(token, false);
-        }
-
-        @Override
-        public void idleFinished(int token) throws RemoteException {
-            if (DEBUG) {
-                Slog.v(TAG, "idleFinished: " + token);
-            }
-            final Message msg = mHandler.obtainMessage(MSG_IDLE_FINISHED, 0, token);
-            mHandler.sendMessage(msg);
-        }
-    }
-
-    // Stuff that we run on a Handler
-    class IdleHandler extends Handler {
-        public IdleHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final int token = msg.arg2;
-
-            switch (msg.what) {
-                case MSG_OP_COMPLETE: {
-                    if (DEBUG) {
-                        Slog.i(TAG, "MSG_OP_COMPLETE of " + token);
-                    }
-                    ActiveTask task = mPendingOperations.get(token);
-                    if (task != null) {
-                        mPendingOperations.remove(token);
-                        removeMessages(MSG_TIMEOUT);
-
-                        handleOpCompleteTm(task, msg.arg1);
-                    } else {
-                        // Can happen in a race between timeout and actual
-                        // (belated) completion of a "begin idling" or similar
-                        // operation.  In that state we've already processed the
-                        // timeout, so we intentionally no-op here.
-                        if (DEBUG) {
-                            Slog.w(TAG, "Belated op-complete of " + token);
-                        }
-                    }
-                    break;
-                }
-
-                case MSG_IDLE_FINISHED: {
-                    if (DEBUG) {
-                        Slog.i(TAG, "MSG_IDLE_FINISHED of " + token);
-                    }
-                    ActiveTask task = mPendingOperations.get(token);
-                    if (task != null) {
-                        if (DEBUG) {
-                            Slog.i(TAG, "... removing task " + token);
-                        }
-                        mPendingOperations.remove(token);
-                        removeMessages(MSG_TIMEOUT);
-
-                        handleIdleFinishedTm(task);
-                    } else {
-                        // Can happen "legitimately" from an app explicitly calling
-                        // idleFinished() after already having been told that its slice
-                        // has ended.
-                        if (DEBUG) {
-                            Slog.w(TAG, "Belated idle-finished of " + token);
-                        }
-                    }
-                    break;
-                }
-
-                case MSG_TIMEOUT: {
-                    if (DEBUG) {
-                        Slog.i(TAG, "MSG_TIMEOUT of " + token);
-                    }
-                    ActiveTask task = mPendingOperations.get(token);
-                    if (task != null) {
-                        mPendingOperations.remove(token);
-                        removeMessages(MSG_OP_COMPLETE);
-
-                        handleTimeoutTm(task);
-                    } else {
-                        // This one should not happen; we flushed timeout messages
-                        // whenever we entered a state after which we have established
-                        // that they are not appropriate.
-                        Slog.w(TAG, "Unexpected timeout of " + token);
-                    }
-                    break;
-                }
-
-                default:
-                    Slog.w(TAG, "Unknown message: " + msg.what);
-            }
-        }
-    }
-
-    void handleTimeoutTm(ActiveTask task) {
-        switch (task.verb) {
-        case VERB_BINDING: {
-            // We were trying to bind to this service, but it wedged or otherwise
-            // failed to respond in time.  Let it stay in the queue for the next
-            // time around, but just give up on it for now and go on to the next.
-            startNextIdleServiceTm();
-            break;
-        }
-        case VERB_IDLING: {
-            // The service has reached the end of its designated idle timeslice.
-            // This is not considered an error.
-            if (DEBUG) {
-                Slog.i(TAG, "Idler reached end of timeslice: " + task.who);
-            }
-            sendEndIdleTm(task.who);
-            break;
-        }
-        case VERB_ENDING: {
-            if (mCurrentIdler == task.who) {
-                if (DEBUG) {
-                    Slog.i(TAG, "Task timed out when ending; unbind needed");
-                }
-                handleIdleFinishedTm(task);
-            } else {
-                if (DEBUG) {
-                    Slog.w(TAG, "Ending timeout for non-current idle service!");
-                }
-            }
-            break;
-        }
-        default: {
-            Slog.w(TAG, "Unknown timeout state " + task.verb);
-            break;
-        }
-        }
-    }
-
-    void handleOpCompleteTm(ActiveTask task, int result) {
-        if (DEBUG) {
-            Slog.i(TAG, "handleOpComplete : task=" + task + " result=" + result);
-        }
-        if (task.verb == VERB_IDLING) {
-            // If the service was told to begin idling and responded positively, then
-            // it has begun idling and will eventually either explicitly finish, or
-            // reach the end of its allotted timeslice.  It's running free now, so we
-            // just schedule the idle-expiration timeout under the token it's already been
-            // given and let it keep going.
-            if (result != 0) {
-                scheduleOpTimeoutTm(task);
-            } else {
-                // The idle service has indicated that it does not, in fact,
-                // need to run at present, so we immediately indicate that it's
-                // to finish idling, and go on to the next idler.
-                if (DEBUG) {
-                    Slog.i(TAG, "Idler declined idling; moving along");
-                }
-                sendEndIdleTm(task.who);
-            }
-        } else {
-            // In the idling case, the task will be cleared either as the result of a timeout
-            // or of an explicit idleFinished().  For all other operations (binding, ending) we
-            // are done with the task as such, so we remove it from our bookkeeping.
-            if (DEBUG) {
-                Slog.i(TAG, "Clearing task " + task);
-            }
-            mPendingOperations.remove(task.token);
-            if (task.verb == VERB_ENDING) {
-                // The last bit of handshaking around idle cessation for this target
-                handleIdleFinishedTm(task);
-            }
-        }
-    }
-
-    void handleIdleFinishedTm(ActiveTask task) {
-        final IdleServiceInfo who = task.who;
-        if (who == mCurrentIdler) {
-            if (DEBUG) {
-                Slog.i(TAG, "Current idler has finished: " + who);
-                Slog.i(TAG, "Attributing wakelock to system work source");
-            }
-            mContext.unbindService(mConnection);
-            startNextIdleServiceTm();
-        } else {
-            Slog.w(TAG, "finish from non-current idle service? " + who);
-        }
-    }
-
-    void updateIdleServiceQueueTm() {
-        if (DEBUG) {
-            Slog.i(TAG, "Updating idle service queue");
-        }
-        PackageManager pm = mContext.getPackageManager();
-        Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
-        List<ResolveInfo> services = pm.queryIntentServices(idleIntent, 0);
-        for (ResolveInfo info : services) {
-            if (info.serviceInfo != null) {
-                if (IdleService.PERMISSION_BIND.equals(info.serviceInfo.permission)) {
-                    final ComponentName componentName = new ComponentName(
-                            info.serviceInfo.packageName,
-                            info.serviceInfo.name);
-                    if (DEBUG) {
-                        Slog.i(TAG, "   - " + componentName);
-                    }
-                    if (!mIdleServices.containsKey(componentName)) {
-                        if (DEBUG) {
-                            Slog.i(TAG, "      + not known; adding");
-                        }
-                        IdleServiceInfo serviceInfo = new IdleServiceInfo(info, componentName);
-                        mIdleServices.put(componentName, serviceInfo);
-                        mIdleServiceQueue.add(serviceInfo);
-                    }
-                } else {
-                    if (DEBUG) {
-                        Slog.i(TAG, "Idle service " + info.serviceInfo
-                                + " does not have required permission; ignoring");
-                    }
-                }
-            }
-        }
-    }
-
-    void startNextIdleServiceTm() {
-        mWakeLock.setWorkSource(mSystemWorkSource);
-
-        if (mLastIdler == null) {
-            // we've run the queue; nothing more to do until the next idle interval.
-            if (DEBUG) {
-                Slog.i(TAG, "Queue already drained; nothing more to do");
-            }
-            return;
-        }
-
-        if (DEBUG) {
-            Slog.i(TAG, "startNextIdleService : last=" + mLastIdler + " cur=" + mCurrentIdler);
-            if (mIdleServiceQueue.size() > 0) {
-                int i = 0;
-                Slog.i(TAG, "Queue (" + mIdleServiceQueue.size() + "):");
-                for (IdleServiceInfo info : mIdleServiceQueue) {
-                    Slog.i(TAG, "   " + i + " : " + info);
-                    i++;
-                }
-            }
-        }
-        if (mCurrentIdler != mLastIdler) {
-            if (mIdleServiceQueue.size() > 0) {
-                IdleServiceInfo target = mIdleServiceQueue.pop();
-                if (DEBUG) {
-                    Slog.i(TAG, "starting next idle service " + target);
-                }
-                Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
-                idleIntent.setComponent(target.componentName);
-                mCurrentIdler = target;
-                ActiveTask task = new ActiveTask(target, VERB_BINDING);
-                scheduleOpTimeoutTm(task);
-                boolean bindOk = mContext.bindServiceAsUser(idleIntent, mConnection,
-                        Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, UserHandle.OWNER);
-                if (!bindOk) {
-                    if (DEBUG) {
-                        Slog.w(TAG, "bindService() to " + target.componentName
-                                + " failed");
-                    }
-                } else {
-                    mIdleServiceQueue.add(target);  // at the end for next time
-                    if (DEBUG) { Slog.i(TAG, "Attributing wakelock to target uid " + target.uid); }
-                    mWakeLock.setWorkSource(new WorkSource(target.uid));
-                }
-            } else {
-                // Queue is empty but mLastIdler is non-null -- eeep.  Clear *everything*
-                // and wind up until the next time around.
-                Slog.e(TAG, "Queue unexpectedly empty; resetting.  last="
-                        + mLastIdler + " cur=" + mCurrentIdler);
-                mHandler.removeMessages(MSG_TIMEOUT);
-                mPendingOperations.clear();
-                stopIdleMaintenanceTm();
-            }
-        } else {
-            // we've reached the place we started, so mark the queue as drained
-            if (DEBUG) {
-                Slog.i(TAG, "Reached end of queue.");
-            }
-            stopIdleMaintenanceTm();
-        }
-    }
-
-    void sendStartIdleTm(IdleServiceInfo who) {
-        ActiveTask task = new ActiveTask(who, VERB_IDLING);
-        scheduleOpTimeoutTm(task);
-        try {
-            who.service.startIdleMaintenance(mCallback, task.token);
-        } catch (RemoteException e) {
-            // We bound to it, but now we can't reach it.  Bail and go on to the
-            // next service.
-            mContext.unbindService(mConnection);
-            if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
-            mHandler.removeMessages(MSG_TIMEOUT);
-            startNextIdleServiceTm();
-        }
-    }
-
-    void sendEndIdleTm(IdleServiceInfo who) {
-        ActiveTask task = new ActiveTask(who, VERB_ENDING);
-        scheduleOpTimeoutTm(task);
-        if (DEBUG) {
-            Slog.i(TAG, "Sending end-idle to " + who);
-        }
-        try {
-            who.service.stopIdleMaintenance(mCallback, task.token);
-        } catch (RemoteException e) {
-            // We bound to it, but now we can't reach it.  Bail and go on to the
-            // next service.
-            mContext.unbindService(mConnection);
-            if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
-            mHandler.removeMessages(MSG_TIMEOUT);
-            startNextIdleServiceTm();
-        }
-    }
-
-    ServiceConnection mConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) {
-                Slog.i(TAG, "onServiceConnected(" + name + ")");
-            }
-            IdleServiceInfo info = mIdleServices.get(name);
-            if (info != null) {
-                // Bound!  Cancel the bind timeout
-                mHandler.removeMessages(MSG_TIMEOUT);
-                // Now tell it to start its idle work
-                info.service = IIdleService.Stub.asInterface(service);
-                sendStartIdleTm(info);
-            } else {
-                // We bound to a service we don't know about.  That's ungood.
-                Slog.e(TAG, "Connected to unexpected component " + name);
-                mContext.unbindService(this);
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) {
-                Slog.i(TAG, "onServiceDisconnected(" + name + ")");
-            }
-            IdleServiceInfo who = mIdleServices.get(name);
-            if (who == mCurrentIdler) {
-                // Hm, okay; they didn't tell us they were finished but they
-                // went away.  Crashed, probably.  Oh well.  They're gone, so
-                // we can't finish them cleanly; just force things along.
-                Slog.w(TAG, "Idler unexpectedly vanished: " + mCurrentIdler);
-                mContext.unbindService(this);
-                mHandler.removeMessages(MSG_TIMEOUT);
-                startNextIdleServiceTm();
-            } else {
-                // Not the current idler, so we don't interrupt our process...
-                if (DEBUG) {
-                    Slog.w(TAG, "Disconnect of abandoned or unexpected service " + name);
-                }
-            }
-        }
-    };
-
-    // Schedules a timeout / end-of-work based on the task verb
-    void scheduleOpTimeoutTm(ActiveTask task) {
-        final long timeoutMillis = (task.verb == VERB_IDLING) ? IDLE_TIMESLICE : OP_TIMEOUT;
-        if (DEBUG) {
-            Slog.i(TAG, "Scheduling timeout (token " + task.token
-                    + " : verb " + task.verb + ") for " + task + " in " + timeoutMillis);
-        }
-        mPendingOperations.put(task.token, task);
-        mHandler.removeMessages(MSG_TIMEOUT);
-        final Message msg = mHandler.obtainMessage(MSG_TIMEOUT, 0, task.token);
-        mHandler.sendMessageDelayed(msg, timeoutMillis);
-    }
-
-    // -------------------------------------------------------------------------------
-    public IdleMaintenanceService(Context context, BatteryService batteryService) {
-        mContext = context;
-        mBatteryService = batteryService;
-
-        mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
-        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
-        mHandler = new IdleHandler(mContext.getMainLooper());
-        mCallback = new IdleCallback();
-
-        Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
-        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
-                intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
-        register(mHandler);
-    }
-
-    public void register(Handler handler) {
-        IntentFilter intentFilter = new IntentFilter();
-
-        // Alarm actions.
-        intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
-
-        // Battery actions.
-        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
-
-        // Screen actions.
-        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-
-        // Dream actions.
-        intentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
-        intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
-
-        mContext.registerReceiverAsUser(this, UserHandle.ALL,
-                intentFilter, null, mHandler);
-
-        intentFilter = new IntentFilter();
-        intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE);
-        mContext.registerReceiverAsUser(this, UserHandle.ALL,
-                intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler);
-    }
-
-    private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
-        final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
-        mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis,
-                mUpdateIdleMaintenanceStatePendingIntent);
-    }
-
-    private void unscheduleUpdateIdleMaintenanceState() {
-        mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
-    }
-
-    private void updateIdleMaintenanceStateTm(boolean noisy) {
-        if (mIdleMaintenanceStarted) {
-            // Idle maintenance can be interrupted by user activity, or duration
-            // time out, or low battery.
-            final boolean batteryOk
-                    = batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning();
-            if (!lastUserActivityPermitsIdleMaintenanceRunning() || !batteryOk) {
-                unscheduleUpdateIdleMaintenanceState();
-                mIdleMaintenanceStarted = false;
-                // We stopped since we don't have enough battery or timed out but the
-                // user is not using the device, so we should be able to run maintenance
-                // in the next maintenance window since the battery may be charged
-                // without interaction and the min interval between maintenances passed.
-                if (!batteryOk) {
-                    scheduleUpdateIdleMaintenanceState(
-                            getNextIdleMaintenanceIntervalStartFromNow());
-                }
-
-                EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
-                        mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
-                        isBatteryCharging() ? 1 : 0);
-                scheduleIdleFinishTm();
-            }
-        } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
-                && lastUserActivityPermitsIdleMaintenanceStart(noisy)
-                && lastRunPermitsIdleMaintenanceStart(noisy)) {
-            // Now that we started idle maintenance, we should schedule another
-            // update for the moment when the idle maintenance times out.
-            scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
-            mIdleMaintenanceStarted = true;
-            EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(),
-                    mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
-                    isBatteryCharging() ? 1 : 0);
-            mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
-            startIdleMaintenanceTm();
-        } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
-             if (lastRunPermitsIdleMaintenanceStart(noisy)) {
-                // The user does not use the device and we did not run maintenance in more
-                // than the min interval between runs, so schedule an update - maybe the
-                // battery will be charged latter.
-                scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
-             } else {
-                 // The user does not use the device but we have run maintenance in the min
-                 // interval between runs, so schedule an update after the min interval ends.
-                 scheduleUpdateIdleMaintenanceState(
-                         getNextIdleMaintenanceIntervalStartFromNow());
-             }
-        }
-    }
-
-    void startIdleMaintenanceTm() {
-        if (DEBUG) {
-            Slog.i(TAG, "*** Starting idle maintenance ***");
-        }
-        if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
-        mWakeLock.setWorkSource(mSystemWorkSource);
-        mWakeLock.acquire();
-        updateIdleServiceQueueTm();
-        mCurrentIdler = null;
-        mLastIdler = (mIdleServiceQueue.size() > 0) ? mIdleServiceQueue.peekLast() : null;
-        startNextIdleServiceTm();
-    }
-
-    // Start a graceful wind-down of the idle maintenance state: end the current idler
-    // and pretend that we've finished running the queue.  If there's no current idler,
-    // this is a no-op.
-    void scheduleIdleFinishTm() {
-        if (mCurrentIdler != null) {
-            if (DEBUG) {
-                Slog.i(TAG, "*** Finishing idle maintenance ***");
-            }
-            mLastIdler = mCurrentIdler;
-            sendEndIdleTm(mCurrentIdler);
-        } else {
-            if (DEBUG) {
-                Slog.w(TAG, "Asked to finish idle maintenance but we're done already");
-            }
-        }
-    }
-
-    // Actual finalization of the idle maintenance sequence
-    void stopIdleMaintenanceTm() {
-        if (mLastIdler != null) {
-            if (DEBUG) {
-                Slog.i(TAG, "*** Idle maintenance shutdown ***");
-            }
-            mWakeLock.setWorkSource(mSystemWorkSource);
-            mLastIdler = mCurrentIdler = null;
-            updateIdleMaintenanceStateTm(false);   // resets 'started' and schedules next window
-            mWakeLock.release();
-        } else {
-            Slog.e(TAG, "ERROR: idle shutdown but invariants not held.  last=" + mLastIdler
-                    + " cur=" + mCurrentIdler + " size=" + mIdleServiceQueue.size());
-        }
-    }
-
-    private long getNextIdleMaintenanceIntervalStartFromNow() {
-        return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS
-                - SystemClock.elapsedRealtime();
-    }
-
-    private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
-        final int minBatteryLevel = isBatteryCharging()
-                ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
-                : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
-        boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
-                && mBatteryService.getBatteryLevel() > minBatteryLevel);
-        if (!allowed && noisy) {
-            Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power");
-        }
-        return allowed;
-    }
-
-    private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
-        // The last time the user poked the device is above the threshold.
-        boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
-                && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
-                    > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
-        if (!allowed && noisy) {
-            Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity");
-        }
-        return allowed;
-    }
-
-    private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
-        // Enough time passed since the last maintenance run.
-        boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
-                > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
-        if (!allowed && noisy) {
-            Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last");
-        }
-        return allowed;
-    }
-
-    private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
-        // The user is not using the device.
-        return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID);
-    }
-
-    private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() {
-        // Battery not too low and the maintenance duration did not timeout.
-        return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING
-                && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION
-                        > SystemClock.elapsedRealtime());
-    }
-
-    private boolean isBatteryCharging() {
-        return mBatteryService.getPlugType() > 0
-                && mBatteryService.getInvalidCharger() == 0;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (DEBUG) {
-            Log.i(TAG, intent.getAction());
-        }
-        String action = intent.getAction();
-        if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
-            // We care about battery only if maintenance is in progress so we can
-            // stop it if battery is too low. Note that here we assume that the
-            // maintenance clients are properly holding a wake lock. We will
-            // refactor the maintenance to use services instead of intents for the
-            // next release. The only client for this for now is internal an holds
-            // a wake lock correctly.
-            if (mIdleMaintenanceStarted) {
-                updateIdleMaintenanceStateTm(false);
-            }
-        } else if (Intent.ACTION_SCREEN_ON.equals(action)
-                || Intent.ACTION_DREAMING_STOPPED.equals(action)) {
-            mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
-            // Unschedule any future updates since we already know that maintenance
-            // cannot be performed since the user is back.
-            unscheduleUpdateIdleMaintenanceState();
-            // If the screen went on/stopped dreaming, we know the user is using the
-            // device which means that idle maintenance should be stopped if running.
-            updateIdleMaintenanceStateTm(false);
-        } else if (Intent.ACTION_SCREEN_OFF.equals(action)
-                || Intent.ACTION_DREAMING_STARTED.equals(action)) {
-            mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
-            // If screen went off/started dreaming, we may be able to start idle maintenance
-            // after the minimal user inactivity elapses. We schedule an alarm for when
-            // this timeout elapses since the device may go to sleep by then.
-            scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
-        } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
-            updateIdleMaintenanceStateTm(false);
-        } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
-            long now = SystemClock.elapsedRealtime() - 1;
-            mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
-            mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
-            updateIdleMaintenanceStateTm(true);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5eee396..10382ba 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -479,8 +479,8 @@
                   mContext,
                   mLocationHandler,
                   flpHardwareProvider.getLocationHardware(),
-                  com.android.internal.R.bool.config_enableFusedLocationOverlay,
-                  com.android.internal.R.string.config_fusedLocationProviderPackageName,
+                  com.android.internal.R.bool.config_enableHardwareFlpOverlay,
+                  com.android.internal.R.string.config_hardwareFlpPackageName,
                   com.android.internal.R.array.config_locationProviderPackageNames);
           if(fusedProxy == null) {
               Slog.e(TAG, "Unable to bind FusedProxy.");
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index 61790826..bcb6e9e 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -18,32 +18,32 @@
 
 import java.util.Calendar;
 
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.app.task.TaskParams;
-import android.app.task.TaskService;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.Context;
 import android.util.Slog;
 
-public class MountServiceIdler extends TaskService {
+public class MountServiceIdler extends JobService {
     private static final String TAG = "MountServiceIdler";
 
     private static ComponentName sIdleService =
             new ComponentName(MountServiceIdler.class.getPackage().getName(),
                     MountServiceIdler.class.getName());
 
-    private static int MOUNT_TASK_ID = 808;
+    private static int MOUNT_JOB_ID = 808;
 
     private boolean mStarted;
-    private TaskParams mTaskParams;
+    private JobParameters mJobParams;
     private Runnable mFinishCallback = new Runnable() {
         @Override
         public void run() {
             Slog.i(TAG, "Got mount service completion callback");
             synchronized (mFinishCallback) {
                 if (mStarted) {
-                    taskFinished(mTaskParams, false);
+                    jobFinished(mJobParams, false);
                     mStarted = false;
                 }
             }
@@ -53,12 +53,12 @@
     };
 
     @Override
-    public boolean onStartTask(TaskParams params) {
+    public boolean onStartJob(JobParameters params) {
         // The mount service will run an fstrim operation asynchronously
         // on a designated separate thread, so we provide it with a callback
         // that lets us cleanly end our idle timeslice.  It's safe to call
         // finishIdle() from any thread.
-        mTaskParams = params;
+        mJobParams = params;
         MountService ms = MountService.sSelf;
         if (ms != null) {
             synchronized (mFinishCallback) {
@@ -70,9 +70,9 @@
     }
 
     @Override
-    public boolean onStopTask(TaskParams params) {
+    public boolean onStopJob(JobParameters params) {
         // Once we kick off the fstrim we aren't actually interruptible; just note
-        // that we don't need to call taskFinished(), and let everything happen in
+        // that we don't need to call jobFinished(), and let everything happen in
         // the callback from the mount service.
         synchronized (mFinishCallback) {
             mStarted = false;
@@ -84,12 +84,12 @@
      * Schedule the idle job that will ping the mount service
      */
     public static void scheduleIdlePass(Context context) {
-        TaskManager tm = (TaskManager) context.getSystemService(Context.TASK_SERVICE);
+        JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
 
         Calendar calendar = tomorrowMidnight();
         final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis();
 
-        Task.Builder builder = new Task.Builder(MOUNT_TASK_ID, sIdleService);
+        JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService);
         builder.setRequiresDeviceIdle(true);
         builder.setRequiresCharging(true);
         builder.setMinimumLatency(timeToMidnight);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 362061e..7022294 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -41,6 +41,7 @@
 import android.net.ConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.InterfaceConfiguration;
+import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.NetworkStats;
 import android.net.NetworkUtils;
@@ -61,6 +62,7 @@
 import android.os.SystemProperties;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -144,6 +146,7 @@
         public static final int InterfaceClassActivity    = 613;
         public static final int InterfaceAddressChange    = 614;
         public static final int InterfaceDnsServerInfo    = 615;
+        public static final int RouteChange               = 616;
     }
 
     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
@@ -237,7 +240,9 @@
         mThread = new Thread(mConnector, NETD_TAG);
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
-        mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+        mPhoneStateListener = new PhoneStateListener(
+                SubscriptionManager.DEFAULT_SUB_ID, // FIXME: What Subscription should be used??
+                mDaemonHandler.getLooper()) {
             public void onDataConnectionRealTimeInfoChanged(
                     DataConnectionRealTimeInfo dcRtInfo) {
                 notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
@@ -577,6 +582,28 @@
         }
     }
 
+    /**
+     * Notify our observers of a route change.
+     */
+    private void notifyRouteChange(String action, RouteInfo route) {
+        final int length = mObservers.beginBroadcast();
+        try {
+            for (int i = 0; i < length; i++) {
+                try {
+                    if (action.equals("updated")) {
+                        mObservers.getBroadcastItem(i).routeUpdated(route);
+                    } else {
+                        mObservers.getBroadcastItem(i).routeRemoved(route);
+                    }
+                } catch (RemoteException e) {
+                } catch (RuntimeException e) {
+                }
+            }
+        } finally {
+            mObservers.finishBroadcast();
+        }
+    }
+
     //
     // Netd Callback handling
     //
@@ -719,6 +746,47 @@
                     }
                     return true;
                     // break;
+            case NetdResponseCode.RouteChange:
+                    /*
+                     * A route has been updated or removed.
+                     * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
+                     */
+                    if (!cooked[1].equals("Route") || cooked.length < 6) {
+                        throw new IllegalStateException(errorMessage);
+                    }
+
+                    String via = null;
+                    String dev = null;
+                    boolean valid = true;
+                    for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
+                        if (cooked[i].equals("dev")) {
+                            if (dev == null) {
+                                dev = cooked[i+1];
+                            } else {
+                                valid = false;  // Duplicate interface.
+                            }
+                        } else if (cooked[i].equals("via")) {
+                            if (via == null) {
+                                via = cooked[i+1];
+                            } else {
+                                valid = false;  // Duplicate gateway.
+                            }
+                        } else {
+                            valid = false;      // Unknown syntax.
+                        }
+                    }
+                    if (valid) {
+                        try {
+                            // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
+                            InetAddress gateway = null;
+                            if (via != null) gateway = InetAddress.parseNumericAddress(via);
+                            RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
+                            notifyRouteChange(cooked[2], route);
+                            return true;
+                        } catch (IllegalArgumentException e) {}
+                    }
+                    throw new IllegalStateException(errorMessage);
+                    // break;
             default: break;
             }
             return false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cfaf016..9d92421 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,10 +33,13 @@
 import android.os.UserHandle;
 import android.telephony.CellLocation;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseCallState;
@@ -65,8 +68,9 @@
  */
 class TelephonyRegistry extends ITelephonyRegistry.Stub {
     private static final String TAG = "TelephonyRegistry";
-    private static final boolean DBG = false;
-    private static final boolean DBG_LOC = false;
+    private static final boolean DBG = false; // STOPSHIP if true
+    private static final boolean DBG_LOC = false; // STOPSHIP if true
+    private static final boolean VDBG = false; // STOPSHIP if true
 
     private static class Record {
         String pkgForDebug;
@@ -79,6 +83,10 @@
 
         int events;
 
+        long subId;
+
+        boolean isLegacyApp;
+
         @Override
         public String toString() {
             return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
@@ -94,41 +102,47 @@
 
     private final IBatteryStats mBatteryStats;
 
-    private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+    private int mNumPhones;
 
-    private String mCallIncomingNumber = "";
+    private int[] mCallState;
 
-    private ServiceState mServiceState = new ServiceState();
+    private String[] mCallIncomingNumber;
 
-    private SignalStrength mSignalStrength = new SignalStrength();
+    private ServiceState[] mServiceState;
 
-    private boolean mMessageWaiting = false;
+    private SignalStrength[] mSignalStrength;
 
-    private boolean mCallForwarding = false;
+    private boolean[] mMessageWaiting;
 
-    private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    private boolean[] mCallForwarding;
 
-    private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
+    private int[] mDataActivity;
 
-    private boolean mDataConnectionPossible = false;
+    private int[] mDataConnectionState;
 
-    private String mDataConnectionReason = "";
+    private boolean[] mDataConnectionPossible;
 
-    private String mDataConnectionApn = "";
+    private String[] mDataConnectionReason;
+
+    private String[] mDataConnectionApn;
 
     private ArrayList<String> mConnectedApns;
 
-    private LinkProperties mDataConnectionLinkProperties;
+    private LinkProperties[] mDataConnectionLinkProperties;
 
-    private NetworkCapabilities mDataConnectionNetworkCapabilities;
+    private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
 
-    private Bundle mCellLocation = new Bundle();
+    private Bundle[] mCellLocation;
 
-    private int mDataConnectionNetworkType;
+    private int[] mDataConnectionNetworkType;
 
     private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
 
-    private List<CellInfo> mCellInfo = null;
+    private ArrayList<List<CellInfo>> mCellInfo = null;
+
+    private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+
+    private long mDefaultSubId;
 
     private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
 
@@ -148,21 +162,40 @@
                 PhoneStateListener.LISTEN_CALL_STATE |
                 PhoneStateListener.LISTEN_DATA_ACTIVITY |
                 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
-                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
+                PhoneStateListener.LISTEN_VOLTE_STATE;;
 
     static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
                 PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
 
     private static final int MSG_USER_SWITCHED = 1;
+    private static final int MSG_UPDATE_DEFAULT_SUB = 2;
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_USER_SWITCHED: {
-                    if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
-                    TelephonyRegistry.this.notifyCellLocation(mCellLocation);
+                    Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+                    int numPhones = TelephonyManager.getDefault().getPhoneCount();
+                    for (int sub = 0; sub < numPhones; sub++) {
+                        TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
+                    }
+                    break;
+                }
+                case MSG_UPDATE_DEFAULT_SUB: {
+                    Slog.d(TAG, "MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
+                    // Default subscription id changed, update the changed default subscription
+                    // id in  all the legacy application listener records.
+                    synchronized (mRecords) {
+                        for (Record r : mRecords) {
+                            // FIXME: Be sure we're using isLegacyApp correctly!
+                            if (r.isLegacyApp == true) {
+                                r.subId = mDefaultSubId;
+                            }
+                        }
+                    }
                     break;
                 }
             }
@@ -173,9 +206,14 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            Slog.d(TAG, "mBroadcastReceiver: action=" + action);
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+            } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
+                mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.getDefaultSubId());
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
             }
         }
     };
@@ -190,13 +228,55 @@
     TelephonyRegistry(Context context) {
         CellLocation  location = CellLocation.getEmpty();
 
+        mContext = context;
+        mBatteryStats = BatteryStatsService.getService();
+        mConnectedApns = new ArrayList<String>();
+
+        // Initialize default subscription to be used for single standby.
+        mDefaultSubId = SubscriptionManager.getDefaultSubId();
+
+        int numPhones = TelephonyManager.getDefault().getPhoneCount();
+        if (DBG) Slog.d(TAG, "TelephonyRegistor: ctor numPhones=" + numPhones);
+        mNumPhones = numPhones;
+        mCallState = new int[numPhones];
+        mDataActivity = new int[numPhones];
+        mDataConnectionState = new int[numPhones];
+        mDataConnectionNetworkType = new int[numPhones];
+        mCallIncomingNumber = new String[numPhones];
+        mServiceState = new ServiceState[numPhones];
+        mSignalStrength = new SignalStrength[numPhones];
+        mMessageWaiting = new boolean[numPhones];
+        mDataConnectionPossible = new boolean[numPhones];
+        mDataConnectionReason = new String[numPhones];
+        mDataConnectionApn = new String[numPhones];
+        mCallForwarding = new boolean[numPhones];
+        mCellLocation = new Bundle[numPhones];
+        mDataConnectionLinkProperties = new LinkProperties[numPhones];
+        mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
+        mCellInfo = new ArrayList<List<CellInfo>>();
+        for (int i = 0; i < numPhones; i++) {
+            mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
+            mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+            mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+            mCallIncomingNumber[i] =  "";
+            mServiceState[i] =  new ServiceState();
+            mSignalStrength[i] =  new SignalStrength();
+            mMessageWaiting[i] =  false;
+            mCallForwarding[i] =  false;
+            mDataConnectionPossible[i] = false;
+            mDataConnectionReason[i] =  "";
+            mDataConnectionApn[i] =  "";
+            mCellLocation[i] = new Bundle();
+            mCellInfo.add(i, null);
+        }
+
         // Note that location can be null for non-phone builds like
         // like the generic one.
         if (location != null) {
-            location.fillInNotifierBundle(mCellLocation);
+            for (int i = 0; i < numPhones; i++) {
+                location.fillInNotifierBundle(mCellLocation[i]);
+            }
         }
-        mContext = context;
-        mBatteryStats = BatteryStatsService.getService();
         mConnectedApns = new ArrayList<String>();
     }
 
@@ -205,16 +285,31 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+        Slog.d(TAG, "systemRunning register for intents");
         mContext.registerReceiver(mBroadcastReceiver, filter);
     }
 
     @Override
     public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
             boolean notifyNow) {
+        listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true);
+    }
+
+    @Override
+    public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback,
+            int events, boolean notifyNow) {
+        listen(pkgForDebug, callback, events, notifyNow, subId, false);
+    }
+
+    private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
+            boolean notifyNow, long subId, boolean isLegacyApp) {
         int callerUid = UserHandle.getCallingUserId();
         int myUid = UserHandle.myUserId();
-        if (DBG) {
+        if (VDBG) {
             Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+                + " notifyNow=" + notifyNow + " subId=" + subId
+                + " isLegacyApp=" + isLegacyApp
                 + " myUid=" + myUid
                 + " callerUid=" + callerUid);
         }
@@ -239,22 +334,37 @@
                     r.callback = callback;
                     r.pkgForDebug = pkgForDebug;
                     r.callerUid = callerUid;
+                    r.subId = subId;
+                    r.isLegacyApp = isLegacyApp;
+                    // Legacy applications pass invalid subId(-1), based on
+                    // the received subId value update the isLegacyApp field
+                    if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
+                        r.subId = mDefaultSubId;
+                        r.isLegacyApp = true; // FIXME: is this needed ??
+                    }
+                    if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+                        r.subId = mDefaultSubId;
+                        if (DBG) Slog.i(TAG, "listen: DEFAULT_SUB_ID");
+                    }
                     mRecords.add(r);
                     if (DBG) Slog.i(TAG, "listen: add new record=" + r);
                 }
+                int phoneId = SubscriptionManager.getPhoneId(subId);
                 int send = events & (events ^ r.events);
                 r.events = events;
-                if (notifyNow) {
+                if (notifyNow && validatePhoneId(phoneId)) {
                     if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                         try {
-                            r.callback.onServiceStateChanged(new ServiceState(mServiceState));
+                            r.callback.onServiceStateChanged(
+                                    new ServiceState(mServiceState[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
                         try {
-                            int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
+                            int gsmSignalStrength = mSignalStrength[phoneId]
+                                    .getGsmSignalStrength();
                             r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
                                     : gsmSignalStrength));
                         } catch (RemoteException ex) {
@@ -263,51 +373,56 @@
                     }
                     if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
                         try {
-                            r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
+                            r.callback.onMessageWaitingIndicatorChanged(
+                                    mMessageWaiting[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
                         try {
-                            r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
+                            r.callback.onCallForwardingIndicatorChanged(
+                                    mCallForwarding[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
                         try {
-                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
-                            r.callback.onCellLocationChanged(new Bundle(mCellLocation));
+                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation = "
+                                    + mCellLocation[phoneId]);
+                            r.callback.onCellLocationChanged(
+                                    new Bundle(mCellLocation[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
                         try {
-                            r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
+                            r.callback.onCallStateChanged(mCallState[phoneId],
+                                     mCallIncomingNumber[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
                         try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
-                                mDataConnectionNetworkType);
+                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                mDataConnectionNetworkType[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                         try {
-                            r.callback.onDataActivity(mDataActivity);
+                            r.callback.onDataActivity(mDataActivity[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
                         try {
-                            r.callback.onSignalStrengthsChanged(mSignalStrength);
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -321,8 +436,9 @@
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
                         try {
-                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
-                            r.callback.onCellInfoChanged(mCellInfo);
+                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo[" + phoneId + "] = "
+                                    + mCellInfo.get(phoneId));
+                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -373,10 +489,10 @@
             return;
         }
         synchronized (mRecords) {
-            mCallState = state;
-            mCallIncomingNumber = incomingNumber;
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+                if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                    (r.isLegacyApp == true)) {
+                    // FIXME: why does isLegacyApp need to be true?
                     try {
                         r.callback.onCallStateChanged(state, incomingNumber);
                     } catch (RemoteException ex) {
@@ -386,82 +502,148 @@
             }
             handleRemoveListLocked();
         }
-        broadcastCallStateChanged(state, incomingNumber);
+        broadcastCallStateChanged(state, incomingNumber, mDefaultSubId);
     }
 
-    public void notifyServiceState(ServiceState state) {
+    public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) {
+        if (!checkNotifyPermission("notifyCallState()")) {
+            return;
+        }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCallStateUsingSubId: subId=" + subId
+                + " state=" + state + " incomingNumber=" + incomingNumber);
+        }
+        synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCallState[phoneId] = state;
+                mCallIncomingNumber[phoneId] = incomingNumber;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                        (r.subId == subId) && (r.isLegacyApp == false)) {
+                        // FIXME: why isLegacyApp false?
+                        try {
+                            r.callback.onCallStateChanged(state, incomingNumber);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+        broadcastCallStateChanged(state, incomingNumber, subId);
+    }
+
+     public void notifyServiceState(ServiceState state) {
+         notifyServiceStateUsingSubId(mDefaultSubId, state);
+     }
+
+    public void notifyServiceStateUsingSubId(long subId, ServiceState state) {
         if (!checkNotifyPermission("notifyServiceState()")){
             return;
         }
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneState(state.getState());
-        } catch (RemoteException re) {
-            // Can't do much
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+        if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
+            subId = mDefaultSubId;
+            Slog.d(TAG, "notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
+        }
+        if (VDBG) {
+            Slog.d(TAG, "notifyServiceStateUsingSubId: subId=" + subId
+                + " state=" + state);
         }
         synchronized (mRecords) {
-            mServiceState = state;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
-                    try {
-                        r.callback.onServiceStateChanged(new ServiceState(state));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mServiceState[phoneId] = state;
+                for (Record r : mRecords) {
+                    // FIXME: use DEFAULT_SUB_ID instead??
+                    if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
+                            (r.subId == subId)) {
+                        try {
+                            r.callback.onServiceStateChanged(new ServiceState(state));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
+            } else {
+                Slog.d(TAG, "notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId);
             }
             handleRemoveListLocked();
         }
-        broadcastServiceStateChanged(state);
+        broadcastServiceStateChanged(state, subId);
     }
 
     public void notifySignalStrength(SignalStrength signalStrength) {
+        notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength);
+    }
+
+    public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) {
         if (!checkNotifyPermission("notifySignalStrength()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifySignalStrengthUsingSubId: subId=" + subId
+                + " signalStrength=" + signalStrength);
+        }
         synchronized (mRecords) {
-            mSignalStrength = signalStrength;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
-                    try {
-                        r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mSignalStrength[phoneId] = signalStrength;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
+                        (r.subId == subId)){
+                        try {
+                            r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
-                }
-                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
-                    try {
-                        int gsmSignalStrength = signalStrength.getGsmSignalStrength();
-                        r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
-                                : gsmSignalStrength));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            int gsmSignalStrength = signalStrength.getGsmSignalStrength();
+                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+                                    : gsmSignalStrength));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
             handleRemoveListLocked();
         }
-        broadcastSignalStrengthChanged(signalStrength);
+        broadcastSignalStrengthChanged(signalStrength, subId);
     }
 
     public void notifyCellInfo(List<CellInfo> cellInfo) {
+         notifyCellInfoUsingSubId(mDefaultSubId, cellInfo);
+    }
+
+    public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) {
         if (!checkNotifyPermission("notifyCellInfo()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCellInfoUsingSubId: subId=" + subId
+                + " cellInfo=" + cellInfo);
+        }
 
         synchronized (mRecords) {
-            mCellInfo = cellInfo;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
-                    try {
-                        if (DBG_LOC) {
-                            Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCellInfo.set(phoneId, cellInfo);
+                for (Record r : mRecords) {
+                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)
+                            && r.subId == subId) {
+                        try {
+                            if (DBG_LOC) {
+                                Slog.d(TAG, "notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
+                            }
+                            r.callback.onCellInfoChanged(cellInfo);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
                         }
-                        r.callback.onCellInfoChanged(cellInfo);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
                     }
                 }
             }
@@ -495,17 +677,29 @@
     }
 
     public void notifyMessageWaitingChanged(boolean mwi) {
+        notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi);
+    }
+
+    public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyMessageWaitingChangedUsingSubId: subId=" + subId
+                + " mwi=" + mwi);
+        }
         synchronized (mRecords) {
-            mMessageWaiting = mwi;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
-                    try {
-                        r.callback.onMessageWaitingIndicatorChanged(mwi);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mMessageWaiting[phoneId] = mwi;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            r.callback.onMessageWaitingIndicatorChanged(mwi);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -514,17 +708,29 @@
     }
 
     public void notifyCallForwardingChanged(boolean cfi) {
+        notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi);
+    }
+
+    public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) {
         if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCallForwardingChangedUsingSubId: subId=" + subId
+                + " cfi=" + cfi);
+        }
         synchronized (mRecords) {
-            mCallForwarding = cfi;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
-                    try {
-                        r.callback.onCallForwardingIndicatorChanged(cfi);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCallForwarding[phoneId] = cfi;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            r.callback.onCallForwardingIndicatorChanged(cfi);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -533,11 +739,16 @@
     }
 
     public void notifyDataActivity(int state) {
+        notifyDataActivityUsingSubId(mDefaultSubId, state);
+    }
+
+    public void notifyDataActivityUsingSubId(long subId, int state) {
         if (!checkNotifyPermission("notifyDataActivity()" )) {
             return;
         }
         synchronized (mRecords) {
-            mDataActivity = state;
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            mDataActivity[phoneId] = state;
             for (Record r : mRecords) {
                 if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                     try {
@@ -554,29 +765,40 @@
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+        notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible,
+            reason, apn, apnType, linkProperties,
+            networkCapabilities, networkType, roaming);
+    }
+
+    public void notifyDataConnectionUsingSubId(long subId, int state,
+            boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+            int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
-        if (DBG) {
-            Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
-                + isDataConnectivityPossible + " reason='" + reason
+        if (VDBG) {
+            Slog.i(TAG, "notifyDataConnectionUsingSubId: subId=" + subId
+                + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
+                + " reason='" + reason
                 + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
                 + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
         }
         synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
             boolean modified = false;
             if (state == TelephonyManager.DATA_CONNECTED) {
                 if (!mConnectedApns.contains(apnType)) {
                     mConnectedApns.add(apnType);
-                    if (mDataConnectionState != state) {
-                        mDataConnectionState = state;
+                    if (mDataConnectionState[phoneId] != state) {
+                        mDataConnectionState[phoneId] = state;
                         modified = true;
                     }
                 }
             } else {
                 if (mConnectedApns.remove(apnType)) {
                     if (mConnectedApns.isEmpty()) {
-                        mDataConnectionState = state;
+                        mDataConnectionState[phoneId] = state;
                         modified = true;
                     } else {
                         // leave mDataConnectionState as is and
@@ -584,25 +806,28 @@
                     }
                 }
             }
-            mDataConnectionPossible = isDataConnectivityPossible;
-            mDataConnectionReason = reason;
-            mDataConnectionLinkProperties = linkProperties;
-            mDataConnectionNetworkCapabilities = networkCapabilities;
-            if (mDataConnectionNetworkType != networkType) {
-                mDataConnectionNetworkType = networkType;
+            mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
+            mDataConnectionReason[phoneId] = reason;
+            mDataConnectionLinkProperties[phoneId] = linkProperties;
+            mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
+            if (mDataConnectionNetworkType[phoneId] != networkType) {
+                mDataConnectionNetworkType[phoneId] = networkType;
                 // need to tell registered listeners about the new network type
                 modified = true;
             }
             if (modified) {
                 if (DBG) {
-                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
-                        + ", " + mDataConnectionNetworkType + ")");
+                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+                        + ", " + mDataConnectionNetworkType[phoneId] + ")");
                 }
                 for (Record r : mRecords) {
-                    if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+                    if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
+                            (r.subId == subId)) {
                         try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
-                                    mDataConnectionNetworkType);
+                            Slog.d(TAG,"Notify data connection state changed on sub: " +
+                                    subId);
+                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                    mDataConnectionNetworkType[phoneId]);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -624,15 +849,24 @@
             handleRemoveListLocked();
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
-                apnType, linkProperties, networkCapabilities, roaming);
+                apnType, linkProperties, networkCapabilities, roaming, subId);
         broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
                 linkProperties, "");
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
+         notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType);
+    }
+
+    public void notifyDataConnectionFailedUsingSubId(long subId,
+            String reason, String apnType) {
         if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyDataConnectionFailedUsingSubId: subId=" + subId
+                + " reason=" + reason + " apnType=" + apnType);
+        }
         synchronized (mRecords) {
             mPreciseDataConnectionState = new PreciseDataConnectionState(
                     TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -648,29 +882,42 @@
             }
             handleRemoveListLocked();
         }
-        broadcastDataConnectionFailed(reason, apnType);
+        broadcastDataConnectionFailed(reason, apnType, subId);
         broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
+         notifyCellLocationUsingSubId(mDefaultSubId, cellLocation);
+    }
+
+    public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) {
+        Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+                + " cellLocation=" + cellLocation);
         if (!checkNotifyPermission("notifyCellLocation()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+                + " cellLocation=" + cellLocation);
+        }
         synchronized (mRecords) {
-            mCellLocation = cellLocation;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
-                    try {
-                        if (DBG_LOC) {
-                            Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
-                                    + " r=" + r);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCellLocation[phoneId] = cellLocation;
+                for (Record r : mRecords) {
+                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)
+                            && r.subId == subId) {
+                        try {
+                            if (DBG_LOC) {
+                                Slog.d(TAG, "notifyCellLocation: cellLocation=" + cellLocation
+                                        + " r=" + r);
+                            }
+                            r.callback.onCellLocationChanged(new Bundle(cellLocation));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
                         }
-                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
                     }
-
                 }
             }
             handleRemoveListLocked();
@@ -771,6 +1018,26 @@
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
     }
 
+    public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
+        if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            mVoLteServiceState = lteState;
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
+                    try {
+                        r.callback.onVoLteServiceStateChanged(
+                                new VoLteServiceState(mVoLteServiceState));
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -810,15 +1077,26 @@
     // the legacy intent broadcasting
     //
 
-    private void broadcastServiceStateChanged(ServiceState state) {
+    private void broadcastServiceStateChanged(ServiceState state, long subId) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneState(state.getState());
+        } catch (RemoteException re) {
+            // Can't do much
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
         intent.putExtras(data);
+        // Pass the subscription along with the intent.
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
+    private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
         long ident = Binder.clearCallingIdentity();
         try {
             mBatteryStats.notePhoneSignalStrength(signalStrength);
@@ -833,10 +1111,11 @@
         Bundle data = new Bundle();
         signalStrength.fillInNotifierBundle(data);
         intent.putExtras(data);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastCallStateChanged(int state, String incomingNumber) {
+    private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
         long ident = Binder.clearCallingIdentity();
         try {
             if (state == TelephonyManager.CALL_STATE_IDLE) {
@@ -856,6 +1135,7 @@
         if (!TextUtils.isEmpty(incomingNumber)) {
             intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
         }
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                 android.Manifest.permission.READ_PHONE_STATE);
     }
@@ -863,7 +1143,7 @@
     private void broadcastDataConnectionStateChanged(int state,
             boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, boolean roaming) {
+            NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -890,13 +1170,16 @@
 
         intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastDataConnectionFailed(String reason, String apnType) {
+    private void broadcastDataConnectionFailed(String reason, String apnType,
+            long subId) {
         Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
         intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
@@ -989,4 +1272,10 @@
         }
         return valid;
     }
+
+    private boolean validatePhoneId(int phoneId) {
+        boolean valid = (phoneId >= 0) && (phoneId < mNumPhones);
+        if (VDBG) Slog.d(TAG, "validatePhoneId: " + valid);
+        return valid;
+    }
 }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b2aaf74..e152ebe 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -537,13 +537,16 @@
     }
 
     @Override
-    public AuthenticatorDescription[] getAuthenticatorTypes() {
+    public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAuthenticatorTypes: "
+                    + "for user id " + userId
                     + "caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        final int userId = UserHandle.getCallingUserId();
+        // Only allow the system process to read accounts of other users
+        enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+                + " trying get authenticator types for " + userId);
         final long identityToken = clearCallingIdentity();
         try {
             Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
@@ -562,6 +565,16 @@
         }
     }
 
+    private void enforceCrossUserPermission(int userId, String errorMessage) {
+        if (userId != UserHandle.getCallingUserId()
+                && Binder.getCallingUid() != Process.myUid()
+                && mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(errorMessage);
+        }
+    }
+
     @Override
     public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1567,14 +1580,8 @@
             final Account account, final Bundle options, final boolean expectActivityLaunch,
             int userId) {
         // Only allow the system process to read accounts of other users
-        if (userId != UserHandle.getCallingUserId()
-                && Binder.getCallingUid() != Process.myUid()
-                && mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                    != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("User " + UserHandle.getCallingUserId()
+        enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
                     + " trying to confirm account credentials for " + userId);
-        }
 
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "confirmCredentials: " + account
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 32722bc..11f855e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -906,6 +906,9 @@
             }
             startTime = 0;
             finishLaunchTickingLocked();
+            if (task != null) {
+                task.hasBeenVisible = true;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 39800f2..03ce530 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -32,12 +32,12 @@
 
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_CONTAINERS;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS;
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
-import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.Watchdog;
@@ -74,6 +74,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Slog;
 import android.view.Display;
@@ -1405,7 +1406,7 @@
 
         ActivityRecord parent = mActivityContainer.mParentActivity;
         if ((parent != null && parent.state != ActivityState.RESUMED) ||
-                !mActivityContainer.isAttached()) {
+                !mActivityContainer.isAttachedLocked()) {
             // Do not resume this stack if its parent is not resumed.
             // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
             return false;
@@ -2677,11 +2678,14 @@
                 || prevState == ActivityState.INITIALIZING) {
             // If this activity is already stopped, we can just finish
             // it right now.
-            boolean activityRemoved = destroyActivityLocked(r, true,
-                    oomAdj, "finish-imm");
+            r.makeFinishing();
+            boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
             if (activityRemoved) {
                 mStackSupervisor.resumeTopActivitiesLocked();
             }
+            if (DEBUG_CONTAINERS) Slog.d(TAG, 
+                    "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
+                    " destroy returned removed=" + activityRemoved);
             return activityRemoved ? null : r;
         }
 
@@ -3044,6 +3048,7 @@
             if (r != null) {
                 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
             }
+            if (DEBUG_CONTAINERS) Slog.d(TAG, "activityDestroyedLocked: r=" + r);
 
             if (isInStackLocked(token) != null) {
                 if (r.state == ActivityState.DESTROYING) {
@@ -3803,7 +3808,7 @@
                 mStacks.remove(this);
                 mStacks.add(0, this);
             }
-            mActivityContainer.onTaskListEmpty();
+            mActivityContainer.onTaskListEmptyLocked();
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index dcdc610..66e9eb3e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -107,10 +107,11 @@
     static final boolean DEBUG = ActivityManagerService.DEBUG || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
     static final boolean DEBUG_APP = DEBUG || false;
-    static final boolean DEBUG_SAVED_STATE = DEBUG || false;
-    static final boolean DEBUG_STATES = DEBUG || false;
+    static final boolean DEBUG_CONTAINERS = DEBUG || false;
     static final boolean DEBUG_IDLE = DEBUG || false;
+    static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
+    static final boolean DEBUG_STATES = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
 
@@ -135,6 +136,7 @@
     static final int LOCK_TASK_START_MSG = FIRST_SUPERVISOR_STACK_MSG + 9;
     static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
     static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 11;
+    static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 12;
 
     private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
 
@@ -239,7 +241,7 @@
 
     // TODO: Add listener for removal of references.
     /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
-    SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+    private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
 
     /** Mapping from displayId to display current state */
     private final SparseArray<ActivityDisplay> mActivityDisplays =
@@ -2255,8 +2257,10 @@
 
     ActivityContainer createActivityContainer(ActivityRecord parentActivity,
             IActivityContainerCallback callback) {
-        ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback);
+        ActivityContainer activityContainer =
+                new VirtualActivityContainer(parentActivity, callback);
         mActivityContainers.put(activityContainer.mStackId, activityContainer);
+        if (DEBUG_CONTAINERS) Slog.d(TAG, "createActivityContainer: " + activityContainer);
         parentActivity.mChildContainers.add(activityContainer);
         return activityContainer;
     }
@@ -2265,6 +2269,8 @@
         final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
         for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
             ActivityContainer container = childStacks.remove(containerNdx);
+            if (DEBUG_CONTAINERS) Slog.d(TAG, "removeChildActivityContainers: removing " +
+                    container);
             container.release();
         }
     }
@@ -2272,11 +2278,8 @@
     void deleteActivityContainer(IActivityContainer container) {
         ActivityContainer activityContainer = (ActivityContainer)container;
         if (activityContainer != null) {
-            activityContainer.mStack.finishAllActivitiesLocked();
-            final ActivityRecord parent = activityContainer.mParentActivity;
-            if (parent != null) {
-                parent.mChildContainers.remove(activityContainer);
-            }
+            if (DEBUG_CONTAINERS) Slog.d(TAG, "deleteActivityContainer: ",
+                    new RuntimeException("here").fillInStackTrace());
             final int stackId = activityContainer.mStackId;
             mActivityContainers.remove(stackId);
             mWindowManager.removeStack(stackId);
@@ -2885,16 +2888,19 @@
 
     @Override
     public void onDisplayAdded(int displayId) {
+        Slog.v(TAG, "Display added displayId=" + displayId);
         mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0));
     }
 
     @Override
     public void onDisplayRemoved(int displayId) {
+        Slog.v(TAG, "Display removed displayId=" + displayId);
         mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0));
     }
 
     @Override
     public void onDisplayChanged(int displayId) {
+        Slog.v(TAG, "Display changed displayId=" + displayId);
         mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
     }
 
@@ -3128,13 +3134,20 @@
                         }
                     }
                 } break;
+                case CONTAINER_TASK_LIST_EMPTY_TIMEOUT: {
+                    synchronized (mService) {
+                        Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
+                                msg.obj);
+                        ((ActivityContainer) msg.obj).onTaskListEmptyLocked();
+                    }
+                } break;
             }
         }
     }
 
     class ActivityContainer extends android.app.IActivityContainer.Stub {
         final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
-                Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+                Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
         final int mStackId;
         IActivityContainerCallback mCallback = null;
         final ActivityStack mStack;
@@ -3184,8 +3197,10 @@
 
         @Override
         public int getDisplayId() {
-            if (mActivityDisplay != null) {
-                return mActivityDisplay.mDisplayId;
+            synchronized (mService) {
+                if (mActivityDisplay != null) {
+                    return mActivityDisplay.mDisplayId;
+                }
             }
             return -1;
         }
@@ -3194,10 +3209,12 @@
         public boolean injectEvent(InputEvent event) {
             final long origId = Binder.clearCallingIdentity();
             try {
-                if (mActivityDisplay != null) {
-                    return mInputManagerInternal.injectInputEvent(event,
-                            mActivityDisplay.mDisplayId,
-                            InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+                synchronized (mService) {
+                    if (mActivityDisplay != null) {
+                        return mInputManagerInternal.injectInputEvent(event,
+                                mActivityDisplay.mDisplayId,
+                                InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+                    }
                 }
                 return false;
             } finally {
@@ -3207,10 +3224,23 @@
 
         @Override
         public void release() {
-            mContainerState = CONTAINER_STATE_FINISHING;
-            mStack.finishAllActivitiesLocked();
-            detachLocked();
-            mWindowManager.removeStack(mStackId);
+            synchronized (mService) {
+                if (mContainerState == CONTAINER_STATE_FINISHING) {
+                    return;
+                }
+                mContainerState = CONTAINER_STATE_FINISHING;
+
+                final Message msg =
+                        mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+                mHandler.sendMessageDelayed(msg, 1000);
+
+                long origId = Binder.clearCallingIdentity();
+                try {
+                    mStack.finishAllActivitiesLocked();
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
+                }
+            }
         }
 
         private void detachLocked() {
@@ -3301,15 +3331,17 @@
             return ActivityStackSupervisor.this;
         }
 
-        boolean isAttached() {
+        boolean isAttachedLocked() {
             return mActivityDisplay != null;
         }
 
         void getBounds(Point outBounds) {
-            if (mActivityDisplay != null) {
-                mActivityDisplay.getBounds(outBounds);
-            } else {
-                outBounds.set(0, 0);
+            synchronized (mService) {
+                    if (mActivityDisplay != null) {
+                    mActivityDisplay.getBounds(outBounds);
+                } else {
+                    outBounds.set(0, 0);
+                }
             }
         }
 
@@ -3332,7 +3364,12 @@
             return true;
         }
 
-        void onTaskListEmpty() {
+        void onTaskListEmptyLocked() {
+            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+            if (!mStack.isHomeStack()) {
+                detachLocked();
+                deleteActivityContainer(this);
+            }
             mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
         }
 
@@ -3351,7 +3388,7 @@
             mParentActivity = parent;
             mCallback = callback;
             mContainerState = CONTAINER_STATE_NO_SURFACE;
-            mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+            mIdString = "VirtualActivityContainer{" + mStackId + ", parent=" + mParentActivity + "}";
         }
 
         @Override
@@ -3397,22 +3434,22 @@
                 }
             }
 
-            setSurfaceIfReady();
+            setSurfaceIfReadyLocked();
 
             if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
                     + virtualActivityDisplay);
         }
 
         @Override
-        boolean isAttached() {
-            return mSurface != null && super.isAttached();
+        boolean isAttachedLocked() {
+            return mSurface != null && super.isAttachedLocked();
         }
 
         @Override
         void setDrawn() {
             synchronized (mService) {
                 mDrawn = true;
-                setSurfaceIfReady();
+                setSurfaceIfReadyLocked();
             }
         }
 
@@ -3422,8 +3459,8 @@
             return false;
         }
 
-        private void setSurfaceIfReady() {
-            if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
+        private void setSurfaceIfReadyLocked() {
+            if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
             if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 79e2d9d..81a0b36 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -73,6 +73,7 @@
     boolean rootWasReset;   // True if the intent at the root of the task had
                             // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
     boolean askedCompatMode;// Have asked the user about compat mode for this task.
+    boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
 
     String stringName;      // caching of toString() result.
     int userId;             // user for which this task was created
@@ -328,8 +329,12 @@
     }
 
     boolean autoRemoveFromRecents() {
-        return intent != null &&
-                (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+        // We will automatically remove the task either if it has explicitly asked for
+        // this, or it is empty and has never contained an activity that got shown to
+        // the user.
+        return (intent != null &&
+                (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0) ||
+                (mActivities.isEmpty() && !hasBeenVisible);
     }
 
     /**
@@ -800,7 +805,8 @@
         }
         pw.print(prefix); pw.print("lastThumbnail="); pw.print(lastThumbnail);
                 pw.print(" lastDescription="); pw.println(lastDescription);
-        pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
+        pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
+                pw.print(" lastActiveTime="); pw.print(lastActiveTime);
                 pw.print(" (inactive for ");
                 pw.print((getInactiveDuration()/1000)); pw.println("s)");
     }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7f43e43..e80aecd 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -111,12 +111,15 @@
         }
     }
 
-    static boolean shouldBlank(int state) {
-        return state == Display.STATE_OFF;
-    }
-
-    static boolean shouldUnblank(int state) {
-        return state == Display.STATE_ON || state == Display.STATE_DOZING;
+    static int getPowerModeForState(int state) {
+        switch (state) {
+            case Display.STATE_OFF:
+                return SurfaceControl.POWER_MODE_OFF;
+            case Display.STATE_DOZING:
+                return SurfaceControl.POWER_MODE_DOZE;
+            default:
+                return SurfaceControl.POWER_MODE_NORMAL;
+        }
     }
 
     private final class LocalDisplayDevice extends DisplayDevice {
@@ -204,11 +207,8 @@
         @Override
         public void requestDisplayStateLocked(int state) {
             if (mState != state) {
-                if (shouldBlank(state) && !shouldBlank(mState)) {
-                    SurfaceControl.blankDisplay(getDisplayTokenLocked());
-                } else if (shouldUnblank(state) && !shouldUnblank(mState)) {
-                    SurfaceControl.unblankDisplay(getDisplayTokenLocked());
-                }
+                SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(),
+                        getPowerModeForState(state));
                 mState = state;
                 updateDeviceInfoLocked();
             }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..2941574
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -0,0 +1,328 @@
+/**
+ * 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.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.IFingerprintService;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends SystemService {
+    private final String TAG = "FingerprintService";
+    private static final boolean DEBUG = true;
+    private ArrayMap<IBinder, ClientData> mClients = new ArrayMap<IBinder, ClientData>();
+
+    private static final int MSG_NOTIFY = 10;
+
+    Handler mHandler = new Handler() {
+        public void handleMessage(android.os.Message msg) {
+            switch (msg.what) {
+                case MSG_NOTIFY:
+                    handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+                    break;
+
+                default:
+                    Slog.w(TAG, "Unknown message:" + msg.what);
+            }
+        }
+    };
+    private Context mContext;
+
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_LISTENING = 1;
+    private static final int STATE_ENROLLING = 2;
+    private static final int STATE_REMOVING = 3;
+    private static final long MS_PER_SEC = 1000;
+    public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+    public static final String ENROLL_FINGERPRINT = "android.permission.ENROLL_FINGERPRINT";
+
+    private static final class ClientData {
+        public IFingerprintServiceReceiver receiver;
+        int state;
+        int userId;
+        public TokenWatcher tokenWatcher;
+        IBinder getToken() { return tokenWatcher.getToken(); }
+    }
+
+    private class TokenWatcher implements IBinder.DeathRecipient {
+        WeakReference<IBinder> token;
+
+        TokenWatcher(IBinder token) {
+            this.token = new WeakReference<IBinder>(token);
+        }
+
+        IBinder getToken() { return token.get(); }
+        public void binderDied() {
+            mClients.remove(token);
+            this.token = null;
+        }
+
+        protected void finalize() throws Throwable {
+            try {
+                if (token != null) {
+                    if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
+                    mClients.remove(token);
+                }
+            } finally {
+                super.finalize();
+            }
+        }
+    }
+
+    public FingerprintService(Context context) {
+        super(context);
+        mContext = context;
+        nativeInit(this);
+    }
+
+    // TODO: Move these into separate process
+    // JNI methods to communicate from FingerprintManagerService to HAL
+    native int nativeEnroll(int timeout);
+    native int nativeEnrollCancel();
+    native int nativeRemove(int fingerprintId);
+    native int nativeOpenHal();
+    native int nativeCloseHal();
+    native void nativeInit(FingerprintService service);
+
+    // JNI methods for communicating from HAL to clients
+    void notify(int msg, int arg1, int arg2) {
+        mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+    }
+
+    void handleNotify(int msg, int arg1, int arg2) {
+        Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
+        for (int i = 0; i < mClients.size(); i++) {
+            ClientData clientData = mClients.valueAt(i);
+            if (clientData == null || clientData.receiver == null) {
+                if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
+                continue;
+            }
+            switch (msg) {
+                case FingerprintManager.FINGERPRINT_ERROR: {
+                    final int error = arg1;
+                    try {
+                        clientData.receiver.onError(error);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "can't send message to client. Did it die?", e);
+                        mClients.remove(mClients.keyAt(i));
+                    }
+                }
+                break;
+                case FingerprintManager.FINGERPRINT_ACQUIRED: {
+                    final int acquireInfo = arg1;
+                    try {
+                        clientData.receiver.onAcquired(acquireInfo);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "can't send message to client. Did it die?", e);
+                        mClients.remove(mClients.keyAt(i));
+                    }
+                    break;
+                }
+                case FingerprintManager.FINGERPRINT_PROCESSED: {
+                    final int fingerId = arg1;
+                    try {
+                        clientData.receiver.onProcessed(fingerId);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "can't send message to client. Did it die?", e);
+                        mClients.remove(mClients.keyAt(i));
+                    }
+                    break;
+                }
+                case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+                    final int fingerId = arg1;
+                    final int remaining = arg2;
+                    if (clientData.state == STATE_ENROLLING) {
+                        // Only send enroll updates to clients that are actually enrolling
+                        try {
+                            clientData.receiver.onEnrollResult(fingerId, remaining);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "can't send message to client. Did it die?", e);
+                            mClients.remove(mClients.keyAt(i));
+                        }
+                        // Update the database with new finger id.
+                        // TODO: move to client code (Settings)
+                        if (remaining == 0) {
+                            FingerprintUtils.addFingerprintIdForUser(fingerId,
+                                    mContext.getContentResolver(), clientData.userId);
+                            clientData.state = STATE_IDLE; // Nothing left to do
+                        }
+                    } else {
+                        if (DEBUG) Slog.w(TAG, "Client not enrolling");
+                        break;
+                    }
+                    break;
+                }
+                case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+                    int fingerId = arg1;
+                    if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+                    FingerprintUtils.removeFingerprintIdForUser(fingerId,
+                            mContext.getContentResolver(), clientData.userId);
+                    if (clientData.receiver != null) {
+                        try {
+                            clientData.receiver.onRemoved(fingerId);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "can't send message to client. Did it die?", e);
+                            mClients.remove(mClients.keyAt(i));
+                        }
+                    }
+                    clientData.state = STATE_LISTENING;
+                }
+                break;
+            }
+        }
+    }
+
+    void startEnroll(IBinder token, long timeout, int userId) {
+        ClientData clientData = mClients.get(token);
+        if (clientData != null) {
+            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+            clientData.state = STATE_ENROLLING;
+            nativeEnroll((int) (timeout / MS_PER_SEC));
+        } else {
+            Slog.w(TAG, "enroll(): No listener registered");
+        }
+    }
+
+    void startEnrollCancel(IBinder token, int userId) {
+        ClientData clientData = mClients.get(token);
+        if (clientData != null) {
+            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+            clientData.state = STATE_LISTENING;
+            nativeEnrollCancel();
+        } else {
+            Slog.w(TAG, "enrollCancel(): No listener registered");
+        }
+    }
+
+    // Remove all fingerprints for the given user.
+    void startRemove(IBinder token, int fingerId, int userId) {
+        ClientData clientData = mClients.get(token);
+        if (clientData != null) {
+            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+            clientData.state = STATE_REMOVING;
+            // The fingerprint id will be removed when we get confirmation from the HAL
+            int result = nativeRemove(fingerId);
+            if (result != 0) {
+                Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
+            }
+        } else {
+            Slog.w(TAG, "remove(" + token + "): No listener registered");
+        }
+    }
+
+    void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
+        if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
+        if (mClients.get(token) == null) {
+            ClientData clientData = new ClientData();
+            clientData.state = STATE_LISTENING;
+            clientData.receiver = receiver;
+            clientData.userId = userId;
+            clientData.tokenWatcher = new TokenWatcher(token);
+            try {
+                token.linkToDeath(clientData.tokenWatcher, 0);
+                mClients.put(token, clientData);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+            }
+        } else {
+            if (DEBUG) Slog.v(TAG, "listener already registered for " + token);
+        }
+    }
+
+    void removeListener(IBinder token, int userId) {
+        if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
+        ClientData clientData = mClients.get(token);
+        if (clientData != null) {
+            token.unlinkToDeath(clientData.tokenWatcher, 0);
+            mClients.remove(token);
+        } else {
+            if (DEBUG) Slog.v(TAG, "listener not registered: " + token);
+        }
+        mClients.remove(token);
+    }
+
+    void checkPermission(String permisison) {
+        // TODO
+    }
+
+    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+        @Override // Binder call
+        public void enroll(IBinder token, long timeout, int userId) {
+            checkPermission(ENROLL_FINGERPRINT);
+            startEnroll(token, timeout, userId);
+        }
+
+        @Override // Binder call
+        public void enrollCancel(IBinder token,int userId) {
+            checkPermission(ENROLL_FINGERPRINT);
+            startEnrollCancel(token, userId);
+        }
+
+        @Override // Binder call
+        public void remove(IBinder token, int fingerprintId, int userId) {
+            checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
+            startRemove(token, fingerprintId, userId);
+        }
+
+        @Override // Binder call
+        public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
+        {
+            checkPermission(USE_FINGERPRINT);
+            addListener(token, receiver, userId);
+        }
+
+        @Override // Binder call
+        public void stopListening(IBinder token, int userId) {
+            checkPermission(USE_FINGERPRINT);
+            removeListener(token, userId);
+        }
+    }
+
+    @Override
+    public void onStart() {
+       publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+       nativeOpenHal();
+    }
+
+}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
new file mode 100644
index 0000000..23cf40b
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -0,0 +1,122 @@
+/*
+ * 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.hdmi;
+
+import android.annotation.Nullable;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Handles CEC command &lt;Active Source&gt;.
+ * <p>
+ * Used by feature actions that need to handle the command in their flow.
+ */
+final class ActiveSourceHandler {
+    private static final String TAG = "ActiveSourceHandler";
+
+    private final HdmiCecLocalDevice mSource;
+    private final HdmiControlService mService;
+    @Nullable
+    private final IHdmiControlCallback mCallback;
+
+    static ActiveSourceHandler create(HdmiCecLocalDevice source,
+            IHdmiControlCallback callback) {
+        if (source == null) {
+            Slog.e(TAG, "Wrong arguments");
+            return null;
+        }
+        return new ActiveSourceHandler(source, callback);
+    }
+
+    private ActiveSourceHandler(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
+        mSource = source;
+        mService = mSource.getService();
+        mCallback = callback;
+    }
+
+    /**
+     * Handles the incoming active source command.
+     *
+     * @param deviceLogicalAddress logical address of the device to be the active source
+     * @param routingPath routing path of the device to be the active source
+     */
+    void process(int deviceLogicalAddress, int routingPath) {
+        if (getSourcePath() == routingPath && mSource.getActiveSource() == getSourceAddress()) {
+            invokeCallback(HdmiCec.RESULT_SUCCESS);
+            return;
+        }
+        HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress);
+        if (device == null) {
+            // "New device action" initiated by <Active Source> does not require
+            // "Routing change action".
+            mSource.addAndStartAction(new NewDeviceAction(mSource, deviceLogicalAddress,
+                    routingPath, false));
+        }
+
+        if (!mSource.isInPresetInstallationMode()) {
+            int prevActiveInput = mSource.getActiveInput();
+            mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
+            if (prevActiveInput != mSource.getActiveInput()) {
+                // TODO: change port input here.
+            }
+            invokeCallback(HdmiCec.RESULT_SUCCESS);
+        } else {
+            // TV is in a mode that should keep its current source/input from
+            // being changed for its operation. Reclaim the active source
+            // or switch the port back to the one used for the current mode.
+            if (mSource.getActiveSource() == getSourceAddress()) {
+                HdmiCecMessage activeSource =
+                        HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
+                                getSourcePath());
+                mService.sendCecCommand(activeSource);
+                mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
+                invokeCallback(HdmiCec.RESULT_SUCCESS);
+            } else {
+                int activePath = mSource.getActivePath();
+                mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
+                        routingPath, activePath));
+                // TODO: Start port select action here
+                // PortSelectAction action = new PortSelectAction(mService, getSourceAddress(),
+                // activePath, mCallback);
+                // mService.addActionAndStart(action);
+            }
+        }
+    }
+
+    private final int getSourceAddress() {
+        return mSource.getDeviceInfo().getLogicalAddress();
+    }
+
+    private final int getSourcePath() {
+        return mSource.getDeviceInfo().getPhysicalAddress();
+    }
+
+    private void invokeCallback(int result) {
+        if (mCallback == null) {
+            return;
+        }
+        try {
+            mCallback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Callback failed:" + e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 6f42c8b..02f088f 100644
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -55,9 +55,6 @@
 
     private static final int DEVICE_POLLING_RETRY = 1;
 
-    // TODO: Move this to common place
-    private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
-
     /**
      * Interface used to report result of device discovery.
      */
@@ -75,7 +72,7 @@
     private static final class DeviceInfo {
         private final int mLogicalAddress;
 
-        private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+        private int mPhysicalAddress = HdmiConstants.INVALID_PHYSICAL_ADDRESS;
         private int mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
         private String mDisplayName = "";
         private int mDeviceType = HdmiCec.DEVICE_INACTIVE;
@@ -97,12 +94,10 @@
     /**
      * Constructor.
      *
-     * @param service an instance of {@link HdmiControlService}.
-     * @param sourceAddress a logical address which initiates this action
+     * @param source an instance of {@link HdmiCecLocalDevice}.
      */
-    DeviceDiscoveryAction(HdmiControlService service, int sourceAddress,
-            DeviceDiscoveryCallback callback) {
-        super(service, sourceAddress);
+    DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
+        super(source);
         mCallback = Preconditions.checkNotNull(callback);
     }
 
@@ -111,7 +106,7 @@
         mDevices.clear();
         mState = STATE_WAITING_FOR_DEVICE_POLLING;
 
-        mService.pollDevices(new DevicePollingCallback() {
+        pollDevices(new DevicePollingCallback() {
             @Override
             public void onPollingFinished(List<Integer> ackedAddress) {
                 if (ackedAddress.isEmpty()) {
@@ -124,7 +119,8 @@
                 allocateDevices(ackedAddress);
                 startPhysicalAddressStage();
             }
-        }, HdmiControlService.POLL_STRATEGY_REMOTES_DEVICES, DEVICE_POLLING_RETRY);
+        }, HdmiConstants.POLL_ITERATION_REVERSE_ORDER
+            | HdmiConstants.POLL_STRATEGY_REMOTES_DEVICES, DEVICE_POLLING_RETRY);
         return true;
     }
 
@@ -159,7 +155,7 @@
         if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS)) {
             return;
         }
-        sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(mSourceAddress, address));
+        sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(), address));
         addTimer(mState, TIMEOUT_MS);
     }
 
@@ -182,7 +178,7 @@
         if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_SET_OSD_NAME)) {
             return;
         }
-        sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress, address));
+        sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(), address));
         addTimer(mState, TIMEOUT_MS);
     }
 
@@ -206,12 +202,13 @@
         if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) {
             return;
         }
-        sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress, address));
+        sendCommand(
+                HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(), address));
         addTimer(mState, TIMEOUT_MS);
     }
 
     private boolean mayProcessMessageIfCached(int address, int opcode) {
-        HdmiCecMessage message = mService.getCecMessageCache().getMessage(address, opcode);
+        HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode);
         if (message != null) {
             processCommand(message);
             return true;
@@ -259,7 +256,7 @@
 
         byte params[] = cmd.getParams();
         if (params.length == 3) {
-            current.mPhysicalAddress = ((params[0] & 0xFF) << 8) | (params[1] & 0xFF);
+            current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
             current.mDeviceType = params[2] & 0xFF;
 
             increaseProcessedDeviceCount();
@@ -307,9 +304,7 @@
 
         byte[] params = cmd.getParams();
         if (params.length == 3) {
-            int vendorId = ((params[0] & 0xFF) << 16)
-                    | ((params[1] & 0xFF) << 8)
-                    | (params[2] & 0xFF);
+            int vendorId = HdmiUtils.threeBytesToInt(params);
             current.mVendorId = vendorId;
         } else {
             Slog.w(TAG, "Invalid vendor id: " + cmd.toString());
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index 63c2182..51df473 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -16,9 +16,10 @@
  * limitations under the License.
  */
 
-import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.HdmiCec;
 import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
 import android.util.Slog;
 
@@ -40,18 +41,18 @@
     private final int mTargetAddress;
     private final IHdmiControlCallback mCallback;
 
-    static DevicePowerStatusAction create(HdmiControlService service, int sourceAddress,
+    static DevicePowerStatusAction create(HdmiCecLocalDevice source,
             int targetAddress, IHdmiControlCallback callback) {
-        if (service == null || callback == null) {
+        if (source == null || callback == null) {
             Slog.e(TAG, "Wrong arguments");
             return null;
         }
-        return new DevicePowerStatusAction(service, sourceAddress, targetAddress, callback);
+        return new DevicePowerStatusAction(source, targetAddress, callback);
     }
 
-    private DevicePowerStatusAction(HdmiControlService service, int sourceAddress,
+    private DevicePowerStatusAction(HdmiCecLocalDevice localDevice,
             int targetAddress, IHdmiControlCallback callback) {
-        super(service, sourceAddress);
+        super(localDevice);
         mTargetAddress = targetAddress;
         mCallback = callback;
     }
@@ -65,8 +66,8 @@
     }
 
     private void queryDevicePowerStatus() {
-        mService.sendCecCommand(
-                HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, mTargetAddress));
+        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
+                mTargetAddress));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
new file mode 100644
index 0000000..dbe3b80
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -0,0 +1,225 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiTvClient;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Handles an action that selects a logical device as a new active source.
+ *
+ * Triggered by {@link HdmiTvClient}, attempts to select the given target device
+ * for a new active source. It does its best to wake up the target in standby mode
+ * before issuing the command &gt;Set Stream path&lt;.
+ */
+final class DeviceSelectAction extends FeatureAction {
+    private static final String TAG = "DeviceSelect";
+
+    // Time in milliseconds we wait for the device power status to switch to 'Standby'
+    private static final int TIMEOUT_TRANSIT_TO_STANDBY_MS = 5 * 1000;
+
+    // Time in milliseconds we wait for the device power status to turn to 'On'.
+    private static final int TIMEOUT_POWER_ON_MS = 5 * 1000;
+
+    // Time in milliseconds we wait for <Active Source>.
+    private static final int TIMEOUT_ACTIVE_SOURCE_MS = 20 * 1000;
+
+    // The number of times we try to wake up the target device before we give up
+    // and just send <Set Stream Path>.
+    private static final int LOOP_COUNTER_MAX = 20;
+
+    // State in which we wait for <Report Power Status> to come in response to the command
+    // <Give Device Power Status> we have sent.
+    private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
+
+    // State in which we wait for the device power status to switch to 'Standby'.
+    // We wait till the status becomes 'Standby' before we send <Set Stream Path>
+    // to wake up the device again.
+    private static final int STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY = 2;
+
+    // State in which we wait for the device power status to switch to 'on'. We wait
+    // maximum 100 seconds (20 * 5) before we give up and just send <Set Stream Path>.
+    private static final int STATE_WAIT_FOR_DEVICE_POWER_ON = 3;
+
+    // State in which we wait for the <Active Source> in response to the command
+    // <Set Stream Path> we have sent. We wait as much as TIMEOUT_ACTIVE_SOURCE_MS
+    // before we give up and mark the action as failure.
+    private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 4;
+
+    private final HdmiCecDeviceInfo mTarget;
+    private final IHdmiControlCallback mCallback;
+
+    private int mPowerStatusCounter = 0;
+
+    /**
+     * Constructor.
+     *
+     * @param source {@link HdmiCecLocalDevice} instance
+     * @param target target logical device that will be a new active source
+     * @param callback callback object
+     */
+    public DeviceSelectAction(HdmiCecLocalDevice source,
+            HdmiCecDeviceInfo target, IHdmiControlCallback callback) {
+        super(source);
+        mCallback = callback;
+        mTarget = target;
+    }
+
+    @Override
+    public boolean start() {
+        // TODO: Call the logic that display a banner saying the select action got started.
+        queryDevicePowerStatus();
+        return true;
+    }
+
+    private void queryDevicePowerStatus() {
+        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+                getSourceAddress(), mTarget.getLogicalAddress()));
+        mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+        addTimer(mState, TIMEOUT_MS);
+    }
+
+    @Override
+    public boolean processCommand(HdmiCecMessage cmd) {
+        if (cmd.getSource() != mTarget.getLogicalAddress()) {
+            return false;
+        }
+        int opcode = cmd.getOpcode();
+        byte[] params = cmd.getParams();
+
+        switch (mState) {
+            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+                if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS && params.length == 1) {
+                    return handleReportPowerStatus(params[0]);
+                }
+                return false;
+            case STATE_WAIT_FOR_ACTIVE_SOURCE:
+                if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE && params.length == 2) {
+                    int activePath = HdmiUtils.twoBytesToInt(params);
+                    ActiveSourceHandler
+                            .create(localDevice(), mCallback)
+                            .process(cmd.getSource(), activePath);
+                    finish();
+                    return true;
+                }
+                return false;
+            default:
+                break;
+        }
+        return false;
+    }
+
+    private boolean handleReportPowerStatus(int powerStatus) {
+        // TODO: Check TV's own status which might have been updated during the action.
+        //       If in 'Standby' or 'Transit to standby', remove the banner
+        //       and stop this action. Otherwise, send <Set Stream Path>
+        switch (powerStatus) {
+            case HdmiCec.POWER_STATUS_ON:
+                sendSetStreamPath();
+                return true;
+            case HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY:
+                if (mPowerStatusCounter < 4) {
+                    mState = STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY;
+                    addTimer(mState, TIMEOUT_TRANSIT_TO_STANDBY_MS);
+                } else {
+                    sendSetStreamPath();
+                }
+                return true;
+            case HdmiCec.POWER_STATUS_STANDBY:
+                if (mPowerStatusCounter == 0) {
+                    turnOnDevice();
+                } else {
+                    sendSetStreamPath();
+                }
+                return true;
+            case HdmiCec.POWER_STATUS_TRANSIENT_TO_ON:
+                if (mPowerStatusCounter < LOOP_COUNTER_MAX) {
+                    mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
+                    addTimer(mState, TIMEOUT_POWER_ON_MS);
+                } else {
+                    sendSetStreamPath();
+                }
+                return true;
+        }
+        return false;
+    }
+
+    private void turnOnDevice() {
+        sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER);
+        sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION);
+        mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
+        addTimer(mState, TIMEOUT_POWER_ON_MS);
+    }
+
+    private void sendSetStreamPath() {
+        sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(
+                getSourceAddress(), mTarget.getPhysicalAddress()));
+        mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
+        addTimer(mState, TIMEOUT_ACTIVE_SOURCE_MS);
+    }
+
+    private void sendRemoteKeyCommand(int keyCode) {
+        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
+                mTarget.getLogicalAddress(), keyCode));
+        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
+                mTarget.getLogicalAddress()));
+    }
+
+    @Override
+    public void handleTimerEvent(int timeoutState) {
+        if (mState != timeoutState) {
+            Slog.w(TAG, "Timer in a wrong state. Ignored.");
+            return;
+        }
+        switch (mState) {
+            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+                sendSetStreamPath();
+                break;
+            case STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY:
+            case STATE_WAIT_FOR_DEVICE_POWER_ON:
+                mPowerStatusCounter++;
+                queryDevicePowerStatus();
+                break;
+            case STATE_WAIT_FOR_ACTIVE_SOURCE:
+                // TODO: Remove the banner
+                //       Display banner "Communication failed. Please check your cable or connection"
+                invokeCallback(HdmiCec.RESULT_TIMEOUT);
+                finish();
+                break;
+        }
+    }
+
+    private void invokeCallback(int result) {
+        if (mCallback == null) {
+            return;
+        }
+        try {
+            mCallback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Callback failed:" + e);
+        }
+    }
+
+    int getTargetAddress() {
+        return mTarget.getLogicalAddress();
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
index 0ba7773..0ec17f6 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -22,6 +22,9 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
+
+import java.util.List;
 
 /**
  * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
@@ -33,21 +36,21 @@
  * of the object. All the actual action classes inherit FeatureAction.
  *
  * <p>More than one FeatureAction objects can be up and running simultaneously,
- * maintained by {@link HdmiControlService}. Each action is passed a new command
+ * maintained by {@link HdmiCecLocalDevice}. Each action is passed a new command
  * arriving from the bus, and either consumes it if the command is what the action expects,
  * or yields it to other action.
  *
  * Declared as package private, accessed by {@link HdmiControlService} only.
  */
 abstract class FeatureAction {
-
     private static final String TAG = "FeatureAction";
 
     // Timer handler message used for timeout event
     protected static final int MSG_TIMEOUT = 100;
 
-    // Default timeout for the incoming command to arrive in response to a request
-    protected static final int TIMEOUT_MS = 1000;
+    // Default timeout for the incoming command to arrive in response to a request.
+    // TODO: Consider reading this value from configuration to allow customization.
+    protected static final int TIMEOUT_MS = 2000;
 
     // Default state used in common by all the feature actions.
     protected static final int STATE_NONE = 0;
@@ -55,19 +58,16 @@
     // Internal state indicating the progress of action.
     protected int mState = STATE_NONE;
 
-    protected final HdmiControlService mService;
-
-    // Logical address of the device for which the feature action is taken. The commands
-    // generated in an action all use this field as source address.
-    protected final int mSourceAddress;
+    private final HdmiControlService mService;
+    private final HdmiCecLocalDevice mSource;
 
     // Timer that manages timeout events.
     protected ActionTimer mActionTimer;
 
-    FeatureAction(HdmiControlService service, int sourceAddress) {
-        mService = service;
-        mSourceAddress = sourceAddress;
-        mActionTimer = createActionTimer(service.getServiceLooper());
+    FeatureAction(HdmiCecLocalDevice source) {
+        mSource = source;
+        mService = mSource.getService();
+        mActionTimer = createActionTimer(mService.getServiceLooper());
     }
 
     @VisibleForTesting
@@ -174,6 +174,42 @@
         mService.sendCecCommand(cmd, callback);
     }
 
+    protected final void addAndStartAction(FeatureAction action) {
+        mSource.addAndStartAction(action);
+    }
+
+    protected final <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+        return mSource.getActions(clazz);
+    }
+
+    protected final HdmiCecMessageCache getCecMessageCache() {
+        return mSource.getCecMessageCache();
+    }
+
+    /**
+     * Remove the action from the action queue. This is called after the action finishes
+     * its role.
+     *
+     * @param action
+     */
+    protected final void removeAction(FeatureAction action) {
+        mSource.removeAction(action);
+    }
+
+    protected final <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+        mSource.removeActionExcept(clazz, null);
+    }
+
+    protected final <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
+            final FeatureAction exception) {
+        mSource.removeActionExcept(clazz, exception);
+    }
+
+    protected final void pollDevices(DevicePollingCallback callback, int pickStrategy,
+            int retryCount) {
+        mService.pollDevices(callback, pickStrategy, retryCount);
+    }
+
     /**
      * Clean up action's state.
      *
@@ -193,13 +229,23 @@
         removeAction(this);
     }
 
-    /**
-     * Remove the action from the action queue. This is called after the action finishes
-     * its role.
-     *
-     * @param action
-     */
-    private void removeAction(FeatureAction action) {
-        mService.removeAction(action);
+    protected final HdmiCecLocalDevice localDevice() {
+        return mSource;
+    }
+
+    protected final HdmiCecLocalDevicePlayback playback() {
+        return (HdmiCecLocalDevicePlayback) mSource;
+    }
+
+    protected final HdmiCecLocalDeviceTv tv() {
+        return (HdmiCecLocalDeviceTv) mSource;
+    }
+
+    protected final int getSourceAddress() {
+        return mSource.getDeviceInfo().getLogicalAddress();
+    }
+
+    protected final int getSourcePath() {
+        return mSource.getDeviceInfo().getPhysicalAddress();
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5c420d7..6d05e82 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -17,8 +17,8 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCec;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
 import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiPortInfo;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
@@ -108,10 +108,6 @@
 
     private HdmiControlService mService;
 
-    // Map-like container of all cec devices including local ones.
-    // A logical address of device is used as key of container.
-    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>();
-
     // Stores the local CEC devices in the system. Device type is used for key.
     private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
 
@@ -223,89 +219,9 @@
         return body;
     }
 
-    /**
-     * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
-     * logical address as new device info's.
-     *
-     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
-     *
-     * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
-     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
-     *         that has the same logical address as new one has.
-     */
-    HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
-        assertRunOnServiceThread();
-        HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
-        if (oldDeviceInfo != null) {
-            removeDeviceInfo(deviceInfo.getLogicalAddress());
-        }
-        mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
-        return oldDeviceInfo;
-    }
 
-    /**
-     * Remove a device info corresponding to the given {@code logicalAddress}.
-     * It returns removed {@link HdmiCecDeviceInfo} if exists.
-     *
-     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
-     *
-     * @param logicalAddress logical address of device to be removed
-     * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
-     */
-    HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
-        assertRunOnServiceThread();
-        HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
-        if (deviceInfo != null) {
-            mDeviceInfos.remove(logicalAddress);
-        }
-        return deviceInfo;
-    }
-
-    /**
-     * Clear all device info.
-     *
-     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
-     */
-    void clearDeviceInfoList() {
-        assertRunOnServiceThread();
-        mDeviceInfos.clear();
-    }
-
-    /**
-     * Return a list of all {@link HdmiCecDeviceInfo}.
-     *
-     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
-     *
-     * @param includeLocalDevice whether to add local device or not
-     */
-    List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) {
-        assertRunOnServiceThread();
-        if (includeLocalDevice) {
-            return sparseArrayToList(mDeviceInfos);
-        } else {
-            ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>();
-            for (int i = 0; i < mDeviceInfos.size(); ++i) {
-                HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i);
-                if (mRemoteDeviceAddressPredicate.apply(info.getLogicalAddress())) {
-                    infoList.add(info);
-                }
-            }
-            return infoList;
-        }
-    }
-
-    /**
-     * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
-     *
-     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
-     *
-     * @param logicalAddress logical address to be retrieved
-     * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
-     *         Returns null if no logical address matched
-     */
-    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
-        assertRunOnServiceThread();
-        return mDeviceInfos.get(logicalAddress);
+    HdmiPortInfo[] getPortInfos() {
+        return nativeGetPortInfos(mNativePtr);
     }
 
     /**
@@ -387,6 +303,41 @@
     }
 
     /**
+     * Pass a option to CEC HAL.
+     *
+     * @param flag a key of option. For more details, look at
+     *        {@link HdmiConstants#FLAG_HDMI_OPTION_WAKEUP} to
+     *        {@link HdmiConstants#FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL}
+     * @param value a value of option. Actual value varies flag. For more
+     *        details, look at description of flags
+     */
+    void setOption(int flag, int value) {
+        assertRunOnServiceThread();
+        nativeSetOption(mNativePtr, flag, value);
+    }
+
+    /**
+     * Configure ARC circuit in the hardware logic to start or stop the feature.
+     *
+     * @param enabled whether to enable/disable ARC
+     */
+    void setAudioReturnChannel(boolean enabled) {
+        assertRunOnServiceThread();
+        nativeSetAudioReturnChannel(mNativePtr, enabled);
+    }
+
+    /**
+     * Return the connection status of the specified port
+     *
+     * @param port port number to check connection status
+     * @return true if connected; otherwise, return false
+     */
+    boolean isConnected(int port) {
+        assertRunOnServiceThread();
+        return nativeIsConnected(mNativePtr, port);
+    }
+
+    /**
      * Poll all remote devices. It sends &lt;Polling Message&gt; to all remote
      * devices.
      *
@@ -411,33 +362,33 @@
      */
     List<HdmiCecLocalDevice> getLocalDeviceList() {
         assertRunOnServiceThread();
-        return sparseArrayToList(mLocalDevices);
+        return HdmiUtils.sparseArrayToList(mLocalDevices);
     }
 
     private List<Integer> pickPollCandidates(int pickStrategy) {
-        int strategy = pickStrategy & HdmiControlService.POLL_STRATEGY_MASK;
+        int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK;
         Predicate<Integer> pickPredicate = null;
         switch (strategy) {
-            case HdmiControlService.POLL_STRATEGY_SYSTEM_AUDIO:
+            case HdmiConstants.POLL_STRATEGY_SYSTEM_AUDIO:
                 pickPredicate = mSystemAudioAddressPredicate;
                 break;
-            case HdmiControlService.POLL_STRATEGY_REMOTES_DEVICES:
+            case HdmiConstants.POLL_STRATEGY_REMOTES_DEVICES:
             default:  // The default is POLL_STRATEGY_REMOTES_DEVICES.
                 pickPredicate = mRemoteDeviceAddressPredicate;
                 break;
         }
 
-        int iterationStrategy = pickStrategy & HdmiControlService.POLL_ITERATION_STRATEGY_MASK;
+        int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK;
         ArrayList<Integer> pollingCandidates = new ArrayList<>();
         switch (iterationStrategy) {
-            case HdmiControlService.POLL_ITERATION_IN_ORDER:
+            case HdmiConstants.POLL_ITERATION_IN_ORDER:
                 for (int i = HdmiCec.ADDR_TV; i <= HdmiCec.ADDR_SPECIFIC_USE; ++i) {
                     if (pickPredicate.apply(i)) {
                         pollingCandidates.add(i);
                     }
                 }
                 break;
-            case HdmiControlService.POLL_ITERATION_REVERSE_ORDER:
+            case HdmiConstants.POLL_ITERATION_REVERSE_ORDER:
             default:  // The default is reverse order.
                 for (int i = HdmiCec.ADDR_SPECIFIC_USE; i >= HdmiCec.ADDR_TV; --i) {
                     if (pickPredicate.apply(i)) {
@@ -449,14 +400,6 @@
         return pollingCandidates;
     }
 
-    private static <T> List<T> sparseArrayToList(SparseArray<T> array) {
-        ArrayList<T> list = new ArrayList<>();
-        for (int i = 0; i < array.size(); ++i) {
-            list.add(array.valueAt(i));
-        }
-        return list;
-    }
-
     private boolean isAllocatedLocalDeviceAddress(int address) {
         for (int i = 0; i < mLocalDevices.size(); ++i) {
             if (mLocalDevices.valueAt(i).isAddressOf(address)) {
@@ -499,7 +442,7 @@
             // new logical address for the device because no device uses
             // it as logical address of the device.
             if (nativeSendCecCommand(mNativePtr, address, address, EMPTY_BODY)
-                    == HdmiControlService.SEND_RESULT_SUCCESS) {
+                    == HdmiConstants.SEND_RESULT_SUCCESS) {
                 return true;
             }
         }
@@ -566,7 +509,7 @@
                 byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                 final int error = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
                         cecMessage.getDestination(), body);
-                if (error != HdmiControlService.SEND_RESULT_SUCCESS) {
+                if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
                     Slog.w(TAG, "Failed to send " + cecMessage);
                 }
                 if (callback != null) {
@@ -606,4 +549,8 @@
     private static native int nativeGetPhysicalAddress(long controllerPtr);
     private static native int nativeGetVersion(long controllerPtr);
     private static native int nativeGetVendorId(long controllerPtr);
+    private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
+    private static native void nativeSetOption(long controllerPtr, int flag, int value);
+    private static native void nativeSetAudioReturnChannel(long controllerPtr, boolean flag);
+    private static native boolean nativeIsConnected(long controllerPtr, int port);
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycodeTranslator.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
similarity index 99%
rename from services/core/java/com/android/server/hdmi/HdmiCecKeycodeTranslator.java
rename to services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index ebb6f50..7080a56 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycodeTranslator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -21,7 +21,7 @@
 /**
  * Helper class to translate android keycode to hdmi cec keycode and vice versa.
  */
-public class HdmiCecKeycodeTranslator {
+public class HdmiCecKeycode {
     public static final int UNSUPPORTED_KEYCODE = -1;
     public static final int NO_PARAM = -1;
 
@@ -151,7 +151,7 @@
     public static final int UI_SOUND_PRESENTATION_TREBLE_NEUTRAL = 0xC2;
     public static final int UI_SOUND_PRESENTATION_TREBLE_STEP_MINUS = 0xC3;
 
-    private HdmiCecKeycodeTranslator() {
+    private HdmiCecKeycode() {
     }
 
     /**
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 23454ad..08d7786 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -18,12 +18,23 @@
 
 import android.hardware.hdmi.HdmiCec;
 import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.Looper;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * Class that models a logical CEC device hosted in this system. Handles initialization,
  * CEC commands that call for actions customized per device type.
  */
 abstract class HdmiCecLocalDevice {
+    private static final String TAG = "HdmiCecLocalDevice";
 
     protected final HdmiControlService mService;
     protected final int mDeviceType;
@@ -31,10 +42,37 @@
     protected int mPreferredAddress;
     protected HdmiCecDeviceInfo mDeviceInfo;
 
+    // Logical address of the active source.
+    @GuardedBy("mLock")
+    private int mActiveSource;
+
+    // Active routing path. Physical address of the active source but not all the time, such as
+    // when the new active source does not claim itself to be one. Note that we don't keep
+    // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}.
+    @GuardedBy("mLock")
+    private int mActiveRoutingPath;
+
+    // Set to true while the service is in normal mode. While set to false, no input change is
+    // allowed. Used for situations where input change can confuse users such as channel auto-scan,
+    // system upgrade, etc., a.k.a. "prohibit mode".
+    @GuardedBy("mLock")
+    private boolean mInputChangeEnabled;
+
+    protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();
+    protected final Object mLock;
+
+    // A collection of FeatureAction.
+    // Note that access to this collection should happen in service thread.
+    private final LinkedList<FeatureAction> mActions = new LinkedList<>();
+
     protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) {
         mService = service;
         mDeviceType = deviceType;
         mAddress = HdmiCec.ADDR_UNREGISTERED;
+        mLock = service.getServiceLock();
+
+        // TODO: Get control flag from persistent storage
+        mInputChangeEnabled = true;
     }
 
     // Factory method that returns HdmiCecLocalDevice of corresponding type.
@@ -59,34 +97,345 @@
      */
     protected abstract void onAddressAllocated(int logicalAddress);
 
+    /**
+     * Dispatch incoming message.
+     *
+     * @param message incoming message
+     * @return true if consumed a message; otherwise, return false.
+     */
+    final boolean dispatchMessage(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        int dest = message.getDestination();
+        if (dest != mAddress && dest != HdmiCec.ADDR_BROADCAST) {
+            return false;
+        }
+        // Cache incoming message. Note that it caches only white-listed one.
+        mCecMessageCache.cacheMessage(message);
+        return onMessage(message);
+    }
+
+    protected final boolean onMessage(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        if (dispatchMessageToAction(message)) {
+            return true;
+        }
+        switch (message.getOpcode()) {
+            case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
+                return handleGetMenuLanguage(message);
+            case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
+                return handleGivePhysicalAddress();
+            case HdmiCec.MESSAGE_GIVE_OSD_NAME:
+                return handleGiveOsdName(message);
+            case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
+                return handleGiveDeviceVendorId();
+            case HdmiCec.MESSAGE_GET_CEC_VERSION:
+                return handleGetCecVersion(message);
+            case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
+                return handleReportPhysicalAddress(message);
+            case HdmiCec.MESSAGE_INITIATE_ARC:
+                return handleInitiateArc(message);
+            case HdmiCec.MESSAGE_TERMINATE_ARC:
+                return handleTerminateArc(message);
+            case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
+                return handleSetSystemAudioMode(message);
+            case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
+                return handleSystemAudioModeStatus(message);
+            default:
+                return false;
+        }
+    }
+
+    private boolean dispatchMessageToAction(HdmiCecMessage message) {
+        for (FeatureAction action : mActions) {
+            if (action.processCommand(message)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected boolean handleGivePhysicalAddress() {
+        assertRunOnServiceThread();
+
+        int physicalAddress = mService.getPhysicalAddress();
+        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+                mAddress, physicalAddress, mDeviceType);
+        mService.sendCecCommand(cecMessage);
+        return true;
+    }
+
+    protected boolean handleGiveDeviceVendorId() {
+        assertRunOnServiceThread();
+
+        int vendorId = mService.getVendorId();
+        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+                mAddress, vendorId);
+        mService.sendCecCommand(cecMessage);
+        return true;
+    }
+
+    protected boolean handleGetCecVersion(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        int version = mService.getCecVersion();
+        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
+                message.getSource(), version);
+        mService.sendCecCommand(cecMessage);
+        return true;
+    }
+
+    protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
+        mService.sendCecCommand(
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
+                        message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
+                        HdmiConstants.ABORT_UNRECOGNIZED_MODE));
+        return true;
+    }
+
+    protected boolean handleGiveOsdName(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        // Note that since this method is called after logical address allocation is done,
+        // mDeviceInfo should not be null.
+        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
+                mAddress, message.getSource(), mDeviceInfo.getDisplayName());
+        if (cecMessage != null) {
+            mService.sendCecCommand(cecMessage);
+        } else {
+            Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName());
+        }
+        return true;
+    }
+
+    protected boolean handleVendorSpecificCommand(HdmiCecMessage message) {
+        return false;
+    }
+
+    protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
+        return false;
+    }
+
+    protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
+        return false;
+    }
+
+    protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
+        return false;
+    }
+
+    protected boolean handleTerminateArc(HdmiCecMessage message) {
+        return false;
+    }
+
+    protected boolean handleInitiateArc(HdmiCecMessage message) {
+        return false;
+    }
+
     final void handleAddressAllocated(int logicalAddress) {
+        assertRunOnServiceThread();
+
         mAddress = mPreferredAddress = logicalAddress;
         onAddressAllocated(logicalAddress);
     }
 
     HdmiCecDeviceInfo getDeviceInfo() {
+        assertRunOnServiceThread();
         return mDeviceInfo;
     }
 
     void setDeviceInfo(HdmiCecDeviceInfo info) {
+        assertRunOnServiceThread();
         mDeviceInfo = info;
     }
 
     // Returns true if the logical address is same as the argument.
     boolean isAddressOf(int addr) {
+        assertRunOnServiceThread();
         return addr == mAddress;
     }
 
     // Resets the logical address to unregistered(15), meaning the logical device is invalid.
     void clearAddress() {
+        assertRunOnServiceThread();
         mAddress = HdmiCec.ADDR_UNREGISTERED;
     }
 
     void setPreferredAddress(int addr) {
+        assertRunOnServiceThread();
         mPreferredAddress = addr;
     }
 
     int getPreferredAddress() {
+        assertRunOnServiceThread();
         return mPreferredAddress;
     }
+
+    void addAndStartAction(final FeatureAction action) {
+        assertRunOnServiceThread();
+        mActions.add(action);
+        action.start();
+    }
+
+    // See if we have an action of a given type in progress.
+    <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
+        assertRunOnServiceThread();
+        for (FeatureAction action : mActions) {
+            if (action.getClass().equals(clazz)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Returns all actions matched with given class type.
+    <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+        assertRunOnServiceThread();
+        ArrayList<T> actions = new ArrayList<>();
+        for (FeatureAction action : mActions) {
+            if (action.getClass().equals(clazz)) {
+                actions.add((T) action);
+            }
+        }
+        return actions;
+    }
+
+    /**
+     * Remove the given {@link FeatureAction} object from the action queue.
+     *
+     * @param action {@link FeatureAction} to remove
+     */
+    void removeAction(final FeatureAction action) {
+        assertRunOnServiceThread();
+        mActions.remove(action);
+    }
+
+    // Remove all actions matched with the given Class type.
+    <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+        removeActionExcept(clazz, null);
+    }
+
+    // Remove all actions matched with the given Class type besides |exception|.
+    <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
+            final FeatureAction exception) {
+        assertRunOnServiceThread();
+        Iterator<FeatureAction> iter = mActions.iterator();
+        while (iter.hasNext()) {
+            FeatureAction action = iter.next();
+            if (action != exception && action.getClass().equals(clazz)) {
+                action.clear();
+                mActions.remove(action);
+            }
+        }
+    }
+
+    protected void assertRunOnServiceThread() {
+        if (Looper.myLooper() != mService.getServiceLooper()) {
+            throw new IllegalStateException("Should run on service thread.");
+        }
+    }
+
+    /**
+     * Called when a hot-plug event issued.
+     *
+     * @param portId id of port where a hot-plug event happened
+     * @param connected whether to connected or not on the event
+     */
+    void onHotplug(int portId, boolean connected) {
+    }
+
+    final HdmiControlService getService() {
+        return mService;
+    }
+
+    final boolean isConnectedToArcPort(int path) {
+        return mService.isConnectedToArcPort(path);
+    }
+
+    int getActiveSource() {
+        synchronized (mLock) {
+            return mActiveSource;
+        }
+    }
+
+    /**
+     * Returns the active routing path.
+     */
+    int getActivePath() {
+        synchronized (mLock) {
+            return mActiveRoutingPath;
+        }
+    }
+
+    /**
+     * Returns the ID of the active HDMI port. The active input is the port that has the active
+     * routing path connected directly or indirectly under the device hierarchy.
+     */
+    int getActiveInput() {
+        synchronized (mLock) {
+            return mService.pathToPortId(mActiveRoutingPath);
+        }
+    }
+
+    void updateActiveDevice(int logicalAddress, int physicalAddress) {
+        synchronized (mLock) {
+            mActiveSource = logicalAddress;
+            mActiveRoutingPath = physicalAddress;
+        }
+    }
+
+    void setInputChangeEnabled(boolean enabled) {
+        synchronized (mLock) {
+            mInputChangeEnabled = enabled;
+        }
+    }
+
+    boolean isInPresetInstallationMode() {
+        synchronized (mLock) {
+            return !mInputChangeEnabled;
+        }
+    }
+
+    /**
+     * Whether the given path is located in the tail of current active path.
+     *
+     * @param path to be tested
+     * @return true if the given path is located in the tail of current active path; otherwise,
+     *         false
+     */
+    // TODO: move this to local device tv.
+    boolean isTailOfActivePath(int path) {
+        synchronized (mLock) {
+            // If active routing path is internal source, return false.
+            if (mActiveRoutingPath == 0) {
+                return false;
+            }
+            for (int i = 12; i >= 0; i -= 4) {
+                int curActivePath = (mActiveRoutingPath >> i) & 0xF;
+                if (curActivePath == 0) {
+                    return true;
+                } else {
+                    int curPath = (path >> i) & 0xF;
+                    if (curPath != curActivePath) {
+                        return false;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    HdmiCecMessageCache getCecMessageCache() {
+        assertRunOnServiceThread();
+        return mCecMessageCache;
+    }
+
+    int pathToPortId(int newPath) {
+        assertRunOnServiceThread();
+        return mService.pathToPortId(newPath);
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d79e283..01345ef 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -17,11 +17,15 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
 
 /**
  * Represent a logical device of type Playback residing in Android system.
  */
 final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
+    private static final String TAG = "HdmiCecLocalDevicePlayback";
 
     HdmiCecLocalDevicePlayback(HdmiControlService service) {
         super(service, HdmiCec.DEVICE_PLAYBACK);
@@ -32,4 +36,54 @@
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
     }
+
+    void oneTouchPlay(IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        if (hasAction(OneTouchPlayAction.class)) {
+            Slog.w(TAG, "oneTouchPlay already in progress");
+            invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
+            return;
+        }
+
+        // TODO: Consider the case of multiple TV sets. For now we always direct the command
+        //       to the primary one.
+        OneTouchPlayAction action = OneTouchPlayAction.create(this, HdmiCec.ADDR_TV, callback);
+        if (action == null) {
+            Slog.w(TAG, "Cannot initiate oneTouchPlay");
+            invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
+            return;
+        }
+        addAndStartAction(action);
+    }
+
+    void queryDisplayStatus(IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        if (hasAction(DevicePowerStatusAction.class)) {
+            Slog.w(TAG, "queryDisplayStatus already in progress");
+            invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
+            return;
+        }
+        DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
+                HdmiCec.ADDR_TV, callback);
+        if (action == null) {
+            Slog.w(TAG, "Cannot initiate queryDisplayStatus");
+            invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
+            return;
+        }
+        addAndStartAction(action);
+    }
+
+    private void invokeCallback(IHdmiControlCallback callback, int result) {
+        try {
+            callback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Invoking callback failed:" + e);
+        }
+    }
+
+    @Override
+    void onHotplug(int portId, boolean connected) {
+        // TODO: clear devices connected to the given port id.
+        mCecMessageCache.flushAll();
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 72d7f2d..92ddd3d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -17,11 +17,38 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
 
 /**
  * Represent a logical device of type TV residing in Android system.
  */
 final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
+    private static final String TAG = "HdmiCecLocalDeviceTv";
+
+    // Whether ARC is "enabled" or not.
+    @GuardedBy("mLock")
+    private boolean mArcStatusEnabled = false;
+
+    @GuardedBy("mLock")
+    // Whether SystemAudioMode is "On" or not.
+    private boolean mSystemAudioMode;
+
+    // Map-like container of all cec devices including local ones.
+    // A logical address of device is used as key of container.
+    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>();
 
     HdmiCecLocalDeviceTv(HdmiControlService service) {
         super(service, HdmiCec.DEVICE_TV);
@@ -29,6 +56,7 @@
 
     @Override
     protected void onAddressAllocated(int logicalAddress) {
+        assertRunOnServiceThread();
         // TODO: vendor-specific initialization here.
 
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
@@ -36,7 +64,396 @@
         mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                 mAddress, mService.getVendorId()));
 
-        mService.launchDeviceDiscovery(mAddress);
+        launchDeviceDiscovery();
         // TODO: Start routing control action, device discovery action.
     }
+
+    /**
+     * Performs the action 'device select', or 'one touch play' initiated by TV.
+     *
+     * @param targetAddress logical address of the device to select
+     * @param callback callback object to report the result with
+     */
+    void deviceSelect(int targetAddress, IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress);
+        if (targetDevice == null) {
+            invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE);
+            return;
+        }
+        removeAction(DeviceSelectAction.class);
+        addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
+    }
+
+    private static void invokeCallback(IHdmiControlCallback callback, int result) {
+        try {
+            callback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Invoking callback failed:" + e);
+        }
+    }
+
+    @Override
+    protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
+                mAddress, Locale.getDefault().getISO3Language());
+        // TODO: figure out how to handle failed to get language code.
+        if (command != null) {
+            mService.sendCecCommand(command);
+        } else {
+            Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        // Ignore if [Device Discovery Action] is going on.
+        if (hasAction(DeviceDiscoveryAction.class)) {
+            Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
+                    + "because Device Discovery Action is on-going:" + message);
+            return true;
+        }
+
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        int logicalAddress = message.getSource();
+
+        // If it is a new device and connected to the tail of active path,
+        // it's required to change routing path.
+        boolean requireRoutingChange = !isInDeviceList(physicalAddress, logicalAddress)
+                && isTailOfActivePath(physicalAddress);
+        addAndStartAction(new NewDeviceAction(this, message.getSource(), physicalAddress,
+                requireRoutingChange));
+        return true;
+    }
+
+    @Override
+    protected boolean handleVendorSpecificCommand(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        List<VendorSpecificAction> actions = Collections.emptyList();
+        // TODO: Call mService.getActions(VendorSpecificAction.class) to get all the actions.
+
+        // We assume that there can be multiple vendor-specific command actions running
+        // at the same time. Pass the message to each action to see if one of them needs it.
+        for (VendorSpecificAction action : actions) {
+            if (action.processCommand(message)) {
+                return true;
+            }
+        }
+        // Handle the message here if it is not already consumed by one of the running actions.
+        // Respond with a appropriate vendor-specific command or <Feature Abort>, or create another
+        // vendor-specific action:
+        //
+        // mService.addAndStartAction(new VendorSpecificAction(mService, mAddress));
+        //
+        // For now, simply reply with <Feature Abort> and mark it consumed by returning true.
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                message.getDestination(), message.getSource(), message.getOpcode(),
+                HdmiConstants.ABORT_REFUSED));
+        return true;
+    }
+
+    private void launchDeviceDiscovery() {
+        assertRunOnServiceThread();
+        clearDeviceInfoList();
+        DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
+                new DeviceDiscoveryCallback() {
+                    @Override
+                    public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) {
+                        for (HdmiCecDeviceInfo info : deviceInfos) {
+                            addCecDevice(info);
+                        }
+
+                        // Since we removed all devices when it's start and
+                        // device discovery action does not poll local devices,
+                        // we should put device info of local device manually here
+                        for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+                            addCecDevice(device.getDeviceInfo());
+                        }
+
+                        addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
+                    }
+                });
+        addAndStartAction(action);
+    }
+
+    // Clear all device info.
+    private void clearDeviceInfoList() {
+        assertRunOnServiceThread();
+        mDeviceInfos.clear();
+    }
+
+    void setSystemAudioMode(boolean on) {
+        synchronized (mLock) {
+            if (on != mSystemAudioMode) {
+                mSystemAudioMode = on;
+                // TODO: Need to set the preference for SystemAudioMode.
+                // TODO: Need to handle the notification of changing the mode and
+                // to identify the notification should be handled in the service or TvSettings.
+            }
+        }
+    }
+
+    boolean getSystemAudioMode() {
+        synchronized (mLock) {
+            assertRunOnServiceThread();
+            return mSystemAudioMode;
+        }
+    }
+
+    /**
+     * Change ARC status into the given {@code enabled} status.
+     *
+     * @return {@code true} if ARC was in "Enabled" status
+     */
+    boolean setArcStatus(boolean enabled) {
+        synchronized (mLock) {
+            boolean oldStatus = mArcStatusEnabled;
+            // 1. Enable/disable ARC circuit.
+            mService.setAudioReturnChannel(enabled);
+
+            // TODO: notify arc mode change to AudioManager.
+
+            // 2. Update arc status;
+            mArcStatusEnabled = enabled;
+            return oldStatus;
+        }
+    }
+
+    /**
+     * Returns whether ARC is enabled or not.
+     */
+    boolean getArcStatus() {
+        synchronized (mLock) {
+            return mArcStatusEnabled;
+        }
+    }
+
+    void setAudioStatus(boolean mute, int volume) {
+        mService.setAudioStatus(mute, volume);
+    }
+
+    @Override
+    protected boolean handleInitiateArc(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        // In case where <Initiate Arc> is started by <Request ARC Initiation>
+        // need to clean up RequestArcInitiationAction.
+        removeAction(RequestArcInitiationAction.class);
+        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
+                message.getSource(), true);
+        addAndStartAction(action);
+        return true;
+    }
+
+    @Override
+    protected boolean handleTerminateArc(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        // In case where <Terminate Arc> is started by <Request ARC Termination>
+        // need to clean up RequestArcInitiationAction.
+        // TODO: check conditions of power status by calling is_connected api
+        // to be added soon.
+        removeAction(RequestArcTerminationAction.class);
+        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
+                message.getSource(), false);
+        addAndStartAction(action);
+        return true;
+    }
+
+    @Override
+    protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        if (!isMessageForSystemAudio(message)) {
+            return false;
+        }
+        SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
+                message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message));
+        addAndStartAction(action);
+        return true;
+    }
+
+    @Override
+    protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        if (!isMessageForSystemAudio(message)) {
+            return false;
+        }
+        setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
+        return true;
+    }
+
+    private boolean isMessageForSystemAudio(HdmiCecMessage message) {
+        if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM
+                || message.getDestination() != HdmiCec.ADDR_TV
+                || getAvrDeviceInfo() == null) {
+            Slog.w(TAG, "Skip abnormal CecMessage: " + message);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
+     * logical address as new device info's.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
+     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
+     *         that has the same logical address as new one has.
+     */
+    HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+        assertRunOnServiceThread();
+        HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
+        if (oldDeviceInfo != null) {
+            removeDeviceInfo(deviceInfo.getLogicalAddress());
+        }
+        mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
+        return oldDeviceInfo;
+    }
+
+    /**
+     * Remove a device info corresponding to the given {@code logicalAddress}.
+     * It returns removed {@link HdmiCecDeviceInfo} if exists.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param logicalAddress logical address of device to be removed
+     * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
+     */
+    HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
+        assertRunOnServiceThread();
+        HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
+        if (deviceInfo != null) {
+            mDeviceInfos.remove(logicalAddress);
+        }
+        return deviceInfo;
+    }
+
+    /**
+     * Return a list of all {@link HdmiCecDeviceInfo}.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     */
+    List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includelLocalDevice) {
+        assertRunOnServiceThread();
+        if (includelLocalDevice) {
+                return HdmiUtils.sparseArrayToList(mDeviceInfos);
+        } else {
+
+            ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>();
+            for (int i = 0; i < mDeviceInfos.size(); ++i) {
+                HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i);
+                if (!isLocalDeviceAddress(info.getLogicalAddress())) {
+                    infoList.add(info);
+                }
+            }
+            return infoList;
+        }
+    }
+
+    private boolean isLocalDeviceAddress(int address) {
+        assertRunOnServiceThread();
+        for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+            if (device.isAddressOf(address)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param logicalAddress logical address to be retrieved
+     * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
+     *         Returns null if no logical address matched
+     */
+    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+        assertRunOnServiceThread();
+        return mDeviceInfos.get(logicalAddress);
+    }
+
+    HdmiCecDeviceInfo getAvrDeviceInfo() {
+        assertRunOnServiceThread();
+        return getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM);
+    }
+
+    /**
+     * Called when a device is newly added or a new device is detected.
+     *
+     * @param info device info of a new device.
+     */
+    final void addCecDevice(HdmiCecDeviceInfo info) {
+        assertRunOnServiceThread();
+        addDeviceInfo(info);
+
+        // TODO: announce new device detection.
+    }
+
+    /**
+     * Called when a device is removed or removal of device is detected.
+     *
+     * @param address a logical address of a device to be removed
+     */
+    final void removeCecDevice(int address) {
+        assertRunOnServiceThread();
+        removeDeviceInfo(address);
+        mCecMessageCache.flushMessagesFrom(address);
+
+        // TODO: announce a device removal.
+    }
+
+    /**
+     * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches
+     * the given routing path. CEC devices use routing path for its physical address to
+     * describe the hierarchy of the devices in the network.
+     *
+     * @param path routing path or physical address
+     * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null
+     */
+    final HdmiCecDeviceInfo getDeviceInfoByPath(int path) {
+        assertRunOnServiceThread();
+        for (HdmiCecDeviceInfo info : getDeviceInfoList(false)) {
+            if (info.getPhysicalAddress() == path) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Whether a device of the specified physical address and logical address exists
+     * in a device info list. However, both are minimal condition and it could
+     * be different device from the original one.
+     *
+     * @param physicalAddress physical address of a device to be searched
+     * @param logicalAddress logical address of a device to be searched
+     * @return true if exist; otherwise false
+     */
+    boolean isInDeviceList(int physicalAddress, int logicalAddress) {
+        assertRunOnServiceThread();
+        HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress);
+        if (device == null) {
+            return false;
+        }
+        return device.getPhysicalAddress() == physicalAddress;
+    }
+
+    @Override
+    void onHotplug(int portNo, boolean connected) {
+        assertRunOnServiceThread();
+        // TODO: delegate onHotplug event to each local device.
+
+        // Tv device will have permanent HotplugDetectionAction.
+        List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class);
+        if (!hotplugActions.isEmpty()) {
+            // Note that hotplug action is single action running on a machine.
+            // "pollAllDevicesNow" cleans up timer and start poll action immediately.
+            hotplugActions.get(0).pollAllDevicesNow();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 1fcb32f..8dbfd85 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -270,6 +270,38 @@
     }
 
     /**
+     * Build &lt;Set Stream Path&gt; command.
+     *
+     * <p>This is a broadcast message sent to all devices on the bus.
+     *
+     * @param src source address of command
+     * @param streamPath physical address of the device to start streaming
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildSetStreamPath(int src, int streamPath) {
+        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_STREAM_PATH,
+                physicalAddressToParam(streamPath));
+    }
+
+    /**
+     * Build &lt;Routing Change&gt; command.
+     *
+     * <p>This is a broadcast message sent to all devices on the bus.
+     *
+     * @param src source address of command
+     * @param oldPath physical address of the currently active routing path
+     * @param newPath physical address of the new active routing path
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildRoutingChange(int src, int oldPath, int newPath) {
+        byte[] param = new byte[] {
+            (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF),
+            (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF)
+        };
+        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ROUTING_CHANGE, param);
+    }
+
+    /**
      * Build &lt;Give Device Power Status&gt; command.
      *
      * @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
index a83d1ed..9c60e55 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConstants.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -39,9 +39,61 @@
 
     // Constants related to UI Command Codes.
     // Refer to CEC Table 30 in HDMI Spec v1.4b.
+    static final int UI_COMMAND_POWER = 0x40;
+    static final int UI_COMMAND_VOLUME_UP = 0x41;
+    static final int UI_COMMAND_VOLUME_DOWN = 0x42;
     static final int UI_COMMAND_MUTE = 0x43;
     static final int UI_COMMAND_MUTE_FUNCTION = 0x65;
     static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66;
+    static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D;
+
+    // Bit mask used to get the routing path of the top level device.
+    // When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
+    static final int ROUTING_PATH_TOP_MASK = 0xF000;
+
+    // Flags used for setOption to CEC HAL.
+    /**
+     * When set to false, HAL does not wake up the system upon receiving
+     * <Image View On> or <Text View On>. Used when user changes the TV
+     * settings to disable the auto TV on functionality.
+     * True by default.
+     */
+    static final int FLAG_HDMI_OPTION_WAKEUP = 1;
+    /**
+     * When set to false, all the CEC commands are discarded. Used when
+     * user changes the TV settings to disable CEC functionality.
+     * True by default.
+     */
+    static final int FLAG_HDMI_OPTION_ENABLE_CEC = 2;
+    /**
+     * Setting this flag to false means Android system will stop handling
+     * CEC service and yield the control over to the microprocessor that is
+     * powered on through the standby mode. When set to true, the system
+     * will gain the control over, hence telling the microprocessor to stop
+     * handling the cec commands. This is called when system goes
+     * in and out of standby mode to notify the microprocessor that it should
+     * start/stop handling CEC commands on behalf of the system.
+     * False by default.
+     */
+    static final int FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL = 3;
+
+    static final int INVALID_PORT_ID = -1;
+    static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+    // Send result codes.
+    static final int SEND_RESULT_SUCCESS = 0;
+    static final int SEND_RESULT_NAK = -1;
+    static final int SEND_RESULT_FAILURE = -2;
+
+    // Strategy for device polling.
+    // Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
+    static final int POLL_STRATEGY_MASK = 0x3;  // first and second bit.
+    static final int POLL_STRATEGY_REMOTES_DEVICES = 0x1;
+    static final int POLL_STRATEGY_SYSTEM_AUDIO = 0x2;
+
+    static final int POLL_ITERATION_STRATEGY_MASK = 0x30000;  // first and second bit.
+    static final int POLL_ITERATION_IN_ORDER = 0x10000;
+    static final int POLL_ITERATION_REVERSE_ORDER = 0x20000;
 
     private HdmiConstants() { /* cannot be instantiated */ }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 58bd5f1..10da756 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -21,9 +21,13 @@
 import android.hardware.hdmi.HdmiCec;
 import android.hardware.hdmi.HdmiCecDeviceInfo;
 import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiHotplugEvent;
+import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.IHdmiControlService;
+import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -33,16 +37,12 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
-import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
 
 import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.Collections;
 import java.util.List;
-import java.util.Locale;
 
 /**
  * Provides a service for sending and processing HDMI control messages,
@@ -54,18 +54,6 @@
     // TODO: Rename the permission to HDMI_CONTROL.
     private static final String PERMISSION = "android.permission.HDMI_CEC";
 
-    static final int SEND_RESULT_SUCCESS = 0;
-    static final int SEND_RESULT_NAK = -1;
-    static final int SEND_RESULT_FAILURE = -2;
-
-    static final int POLL_STRATEGY_MASK = 0x3;  // first and second bit.
-    static final int POLL_STRATEGY_REMOTES_DEVICES = 0x1;
-    static final int POLL_STRATEGY_SYSTEM_AUDIO = 0x2;
-
-    static final int POLL_ITERATION_STRATEGY_MASK = 0x30000;  // first and second bit.
-    static final int POLL_ITERATION_IN_ORDER = 0x10000;
-    static final int POLL_ITERATION_REVERSE_ORDER = 0x20000;
-
     /**
      * Interface to report send result.
      */
@@ -98,16 +86,11 @@
     // and sparse call it shares a thread to handle IO operations.
     private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
 
-    // A collection of FeatureAction.
-    // Note that access to this collection should happen in service thread.
-    private final LinkedList<FeatureAction> mActions = new LinkedList<>();
-
     // Used to synchronize the access to the service.
     private final Object mLock = new Object();
 
-    // Type of logical devices hosted in the system.
-    @GuardedBy("mLock")
-    private final int[] mLocalDevices;
+    // Type of logical devices hosted in the system. Stored in the unmodifiable list.
+    private final List<Integer> mLocalDevices;
 
     // List of listeners registered by callers that want to get notified of
     // hotplug events.
@@ -117,7 +100,16 @@
     private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
             new ArrayList<>();
 
-    private final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();
+    // List of listeners registered by callers that want to get notified of
+    // device status events.
+    private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>();
+
+    // List of records for device event listener to handle the the caller killed in action.
+    private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
+            new ArrayList<>();
+
+    // Handler running on service thread. It's used to run a task in service thread.
+    private final Handler mHandler = new Handler();
 
     @Nullable
     private HdmiCecController mCecController;
@@ -125,22 +117,14 @@
     @Nullable
     private HdmiMhlController mMhlController;
 
-    @GuardedBy("mLock")
-    // Whether ARC is "enabled" or not.
-    // TODO: it may need to hold lock if it's accessed from others.
-    private boolean mArcStatusEnabled = false;
-
-    @GuardedBy("mLock")
-    // Whether SystemAudioMode is "On" or not.
-    private boolean mSystemAudioMode;
-
-    // Handler running on service thread. It's used to run a task in service thread.
-    private final Handler mHandler = new Handler();
+    // HDMI port information. Stored in the unmodifiable list to keep the static information
+    // from being modified.
+    private List<HdmiPortInfo> mPortInfo;
 
     public HdmiControlService(Context context) {
         super(context);
-        mLocalDevices = getContext().getResources().getIntArray(
-                com.android.internal.R.array.config_hdmiCecLogicalDeviceType);
+        mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray(
+                com.android.internal.R.array.config_hdmiCecLogicalDeviceType));
     }
 
     @Override
@@ -158,14 +142,14 @@
         if (mMhlController == null) {
             Slog.i(TAG, "Device does not support MHL-control.");
         }
-
+        mPortInfo = initPortInfo();
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
 
         // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and
         // start to monitor the preference value and invoke SystemAudioActionFromTv if needed.
     }
 
-    private void initializeLocalDevices(final int[] deviceTypes) {
+    private void initializeLocalDevices(final List<Integer> deviceTypes) {
         // A container for [Logical Address, Local device info].
         final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>();
         final SparseIntArray finished = new SparseIntArray();
@@ -189,7 +173,7 @@
 
                     // Once finish address allocation for all devices, notify
                     // it to each device.
-                    if (deviceTypes.length == finished.size()) {
+                    if (deviceTypes.size() == finished.size()) {
                         notifyAddressAllocated(devices);
                     }
                 }
@@ -205,6 +189,95 @@
         }
     }
 
+    // Initialize HDMI port information. Combine the information from CEC and MHL HAL and
+    // keep them in one place.
+    private List<HdmiPortInfo> initPortInfo() {
+        HdmiPortInfo[] cecPortInfo = null;
+
+        // CEC HAL provides majority of the info while MHL does only MHL support flag for
+        // each port. Return empty array if CEC HAL didn't provide the info.
+        if (mCecController != null) {
+            cecPortInfo = mCecController.getPortInfos();
+        }
+        if (cecPortInfo == null) {
+            return Collections.emptyList();
+        }
+
+        HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0];
+        if (mMhlController != null) {
+            // TODO: Implement plumbing logic to get MHL port information.
+            // mhlPortInfo = mMhlController.getPortInfos();
+        }
+
+        // Use the id (port number) to find the matched info between CEC and MHL to combine them
+        // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found.
+        ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length);
+        for (int i = 0; i < cecPortInfo.length; ++i) {
+            HdmiPortInfo cec = cecPortInfo[i];
+            int id = cec.getId();
+            boolean mhlInfoFound = false;
+            for (HdmiPortInfo mhl : mhlPortInfo) {
+                if (id == mhl.getId()) {
+                    result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(),
+                            cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported()));
+                    mhlInfoFound = true;
+                    break;
+                }
+            }
+            if (!mhlInfoFound) {
+                result.add(cec);
+            }
+        }
+
+        return Collections.unmodifiableList(result);
+    }
+
+    /**
+     * Returns HDMI port information for the given port id.
+     *
+     * @param portId HDMI port id
+     * @return {@link HdmiPortInfo} for the given port
+     */
+    HdmiPortInfo getPortInfo(int portId) {
+        // mPortInfo is an unmodifiable list and the only reference to its inner list.
+        // No lock is necessary.
+        for (HdmiPortInfo info : mPortInfo) {
+            if (portId == info.getId()) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the routing path (physical address) of the HDMI port for the given
+     * port id.
+     */
+    int portIdToPath(int portId) {
+        HdmiPortInfo portInfo = getPortInfo(portId);
+        if (portInfo == null) {
+            Slog.e(TAG, "Cannot find the port info: " + portId);
+            return HdmiConstants.INVALID_PHYSICAL_ADDRESS;
+        }
+        return portInfo.getAddress();
+    }
+
+    /**
+     * Returns the id of HDMI port located at the top of the hierarchy of
+     * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance,
+     * the port id to be returned is the ID associated with the port address
+     * 0x1000 (1.0.0.0) which is the topmost path of the given routing path.
+     */
+    int pathToPortId(int path) {
+        int portAddress = path & HdmiConstants.ROUTING_PATH_TOP_MASK;
+        for (HdmiPortInfo info : mPortInfo) {
+            if (portAddress == info.getAddress()) {
+                return info.getId();
+            }
+        }
+        return HdmiConstants.INVALID_PORT_ID;
+    }
+
     /**
      * Returns {@link Looper} for IO operation.
      *
@@ -238,84 +311,36 @@
         return mCecController.getVendorId();
     }
 
-    /**
-     * Returns a list of {@link HdmiCecDeviceInfo}.
-     *
-     * @param includeLocalDevice whether to include local devices
-     */
-    List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) {
+    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
         assertRunOnServiceThread();
-        return mCecController.getDeviceInfoList(includeLocalDevice);
+        HdmiCecLocalDeviceTv tv = tv();
+        if (tv == null) {
+            return null;
+        }
+        return tv.getDeviceInfo(logicalAddress);
     }
 
     /**
-     * Add and start a new {@link FeatureAction} to the action queue.
-     *
-     * @param action {@link FeatureAction} to add and start
+     * Returns version of CEC.
      */
-    void addAndStartAction(final FeatureAction action) {
-        // TODO: may need to check the number of stale actions.
-        runOnServiceThread(new Runnable() {
-            @Override
-            public void run() {
-                mActions.add(action);
-                action.start();
-            }
-        });
+    int getCecVersion() {
+        return mCecController.getVersion();
     }
 
-    void setSystemAudioMode(boolean on) {
-        synchronized (mLock) {
-            mSystemAudioMode = on;
-        }
-    }
-
-    boolean getSystemAudioMode() {
-        synchronized (mLock) {
-            return mSystemAudioMode;
-        }
-    }
-
-    // See if we have an action of a given type in progress.
-    private <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
-        for (FeatureAction action : mActions) {
-            if (action.getClass().equals(clazz)) {
+    /**
+     * Whether a device of the specified physical address is connected to ARC enabled port.
+     */
+    boolean isConnectedToArcPort(int physicalAddress) {
+        for (HdmiPortInfo portInfo : mPortInfo) {
+            if (hasSameTopPort(portInfo.getAddress(), physicalAddress)
+                    && portInfo.isArcSupported()) {
                 return true;
             }
         }
         return false;
     }
 
-    /**
-     * Remove the given {@link FeatureAction} object from the action queue.
-     *
-     * @param action {@link FeatureAction} to remove
-     */
-    void removeAction(final FeatureAction action) {
-        assertRunOnServiceThread();
-        mActions.remove(action);
-    }
-
-    // Remove all actions matched with the given Class type.
-    private <T extends FeatureAction> void removeAction(final Class<T> clazz) {
-        removeActionExcept(clazz, null);
-    }
-
-    // Remove all actions matched with the given Class type besides |exception|.
-    <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
-            final FeatureAction exception) {
-        assertRunOnServiceThread();
-        Iterator<FeatureAction> iter = mActions.iterator();
-        while (iter.hasNext()) {
-            FeatureAction action = iter.next();
-            if (action != exception && action.getClass().equals(clazz)) {
-                action.clear();
-                mActions.remove(action);
-            }
-        }
-    }
-
-    private void runOnServiceThread(Runnable runnable) {
+    void runOnServiceThread(Runnable runnable) {
         mHandler.post(runnable);
     }
 
@@ -330,23 +355,6 @@
     }
 
     /**
-     * Change ARC status into the given {@code enabled} status.
-     *
-     * @return {@code true} if ARC was in "Enabled" status
-     */
-    boolean setArcStatus(boolean enabled) {
-        synchronized (mLock) {
-            boolean oldStatus = mArcStatusEnabled;
-            // 1. Enable/disable ARC circuit.
-            // TODO: call set_audio_return_channel of hal interface.
-
-            // 2. Update arc status;
-            mArcStatusEnabled = enabled;
-            return oldStatus;
-        }
-    }
-
-    /**
      * Transmit a CEC command to CEC bus.
      *
      * @param command CEC command to send out
@@ -361,45 +369,23 @@
     }
 
     boolean handleCecCommand(HdmiCecMessage message) {
-        // Cache incoming message. Note that it caches only white-listed one.
-        mCecMessageCache.cacheMessage(message);
+        return dispatchMessageToLocalDevice(message);
+    }
 
-        // Commands that queries system information replies directly instead
-        // of creating FeatureAction because they are state-less.
-        switch (message.getOpcode()) {
-            case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
-                handleGetMenuLanguage(message);
+    void setAudioReturnChannel(boolean enabled) {
+        mCecController.setAudioReturnChannel(enabled);
+    }
+
+    private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) {
+        for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
+            if (device.dispatchMessage(message)
+                    && message.getDestination() != HdmiCec.ADDR_BROADCAST) {
                 return true;
-            case HdmiCec.MESSAGE_GIVE_OSD_NAME:
-                handleGiveOsdName(message);
-                return true;
-            case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
-                handleGivePhysicalAddress(message);
-                return true;
-            case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
-                handleGiveDeviceVendorId(message);
-                return true;
-            case HdmiCec.MESSAGE_GET_CEC_VERSION:
-                handleGetCecVersion(message);
-                return true;
-            case HdmiCec.MESSAGE_INITIATE_ARC:
-                handleInitiateArc(message);
-                return true;
-            case HdmiCec.MESSAGE_TERMINATE_ARC:
-                handleTerminateArc(message);
-                return true;
-            case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
-                handleReportPhysicalAddress(message);
-                return true;
-            case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
-                handleSetSystemAudioMode(message);
-                return true;
-            case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
-                handleSystemAudioModeStatus(message);
-                return true;
-            default:
-                return dispatchMessageToAction(message);
+            }
         }
+
+        Slog.w(TAG, "Unhandled cec command:" + message);
+        return false;
     }
 
     /**
@@ -409,7 +395,13 @@
      * @param connected whether to be plugged in or not
      */
     void onHotplug(int portNo, boolean connected) {
-        // TODO: Start "RequestArcInitiationAction" if ARC port.
+        assertRunOnServiceThread();
+
+        for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
+            device.onHotplug(portNo, connected);
+        }
+
+        announceHotplugEvent(portNo, connected);
     }
 
     /**
@@ -426,187 +418,37 @@
     }
 
     private int checkPollStrategy(int pickStrategy) {
-        int strategy = pickStrategy & POLL_STRATEGY_MASK;
+        int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK;
         if (strategy == 0) {
             throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy);
         }
-        int iterationStrategy = pickStrategy & POLL_ITERATION_STRATEGY_MASK;
+        int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK;
         if (iterationStrategy == 0) {
             throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy);
         }
         return strategy | iterationStrategy;
     }
 
-    /**
-     * Launch device discovery sequence. It starts with clearing the existing device info list.
-     * Note that it assumes that logical address of all local devices is already allocated.
-     *
-     * @param sourceAddress a logical address of tv
-     */
-    void launchDeviceDiscovery(final int sourceAddress) {
-        // At first, clear all existing device infos.
-        mCecController.clearDeviceInfoList();
-        mCecMessageCache.flushAll();
+    List<HdmiCecLocalDevice> getAllLocalDevices() {
+        assertRunOnServiceThread();
+        return mCecController.getLocalDeviceList();
+    }
 
-        // TODO: check whether TV is one of local devices.
-        DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress,
-                new DeviceDiscoveryCallback() {
-                    @Override
-                    public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) {
-                        for (HdmiCecDeviceInfo info : deviceInfos) {
-                            addCecDevice(info);
-                        }
+    Object getServiceLock() {
+        return mLock;
+    }
 
-                        // Add device info of all local devices.
-                        for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
-                            addCecDevice(device.getDeviceInfo());
-                        }
-
-                        addAndStartAction(new HotplugDetectionAction(HdmiControlService.this,
-                                sourceAddress));
-                    }
-                });
-        addAndStartAction(action);
+    void setAudioStatus(boolean mute, int volume) {
+        // TODO: Hook up with AudioManager.
     }
 
     private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
-        // TODO: get device name read from system configuration.
-        String displayName = HdmiCec.getDefaultDeviceName(logicalAddress);
+        // TODO: find better name instead of model name.
+        String displayName = Build.MODEL;
         return new HdmiCecDeviceInfo(logicalAddress,
                 getPhysicalAddress(), deviceType, getVendorId(), displayName);
     }
 
-    private void handleReportPhysicalAddress(HdmiCecMessage message) {
-        // At first, try to consume it.
-        if (dispatchMessageToAction(message)) {
-            return;
-        }
-
-        // Ignore if [Device Discovery Action] is going on.
-        if (hasAction(DeviceDiscoveryAction.class)) {
-            Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
-                    + "because Device Discovery Action is on-going:" + message);
-            return;
-        }
-
-        // TODO: start new device action.
-    }
-
-    private void handleInitiateArc(HdmiCecMessage message){
-        // In case where <Initiate Arc> is started by <Request ARC Initiation>
-        // need to clean up RequestArcInitiationAction.
-        removeAction(RequestArcInitiationAction.class);
-        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
-                message.getDestination(), message.getSource(), true);
-        addAndStartAction(action);
-    }
-
-    private void handleTerminateArc(HdmiCecMessage message) {
-        // In case where <Terminate Arc> is started by <Request ARC Termination>
-        // need to clean up RequestArcInitiationAction.
-        // TODO: check conditions of power status by calling is_connected api
-        // to be added soon.
-        removeAction(RequestArcTerminationAction.class);
-        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
-                message.getDestination(), message.getSource(), false);
-        addAndStartAction(action);
-    }
-
-    private void handleGetCecVersion(HdmiCecMessage message) {
-        int version = mCecController.getVersion();
-        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
-                message.getSource(),
-                version);
-        sendCecCommand(cecMessage);
-    }
-
-    private void handleGiveDeviceVendorId(HdmiCecMessage message) {
-        int vendorId = mCecController.getVendorId();
-        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
-                message.getDestination(), vendorId);
-        sendCecCommand(cecMessage);
-    }
-
-    private void handleGivePhysicalAddress(HdmiCecMessage message) {
-        int physicalAddress = mCecController.getPhysicalAddress();
-        int deviceType = HdmiCec.getTypeFromAddress(message.getDestination());
-        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
-                message.getDestination(), physicalAddress, deviceType);
-        sendCecCommand(cecMessage);
-    }
-
-    private void handleGiveOsdName(HdmiCecMessage message) {
-        // TODO: read device name from settings or property.
-        String name = HdmiCec.getDefaultDeviceName(message.getDestination());
-        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
-                message.getDestination(), message.getSource(), name);
-        if (cecMessage != null) {
-            sendCecCommand(cecMessage);
-        } else {
-            Slog.w(TAG, "Failed to build <Get Osd Name>:" + name);
-        }
-    }
-
-    private void handleGetMenuLanguage(HdmiCecMessage message) {
-        // Only 0 (TV), 14 (specific use) can answer.
-        if (message.getDestination() != HdmiCec.ADDR_TV
-                && message.getDestination() != HdmiCec.ADDR_SPECIFIC_USE) {
-            Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
-            sendCecCommand(
-                    HdmiCecMessageBuilder.buildFeatureAbortCommand(message.getDestination(),
-                            message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
-                            HdmiConstants.ABORT_UNRECOGNIZED_MODE));
-            return;
-        }
-
-        HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
-                message.getDestination(),
-                Locale.getDefault().getISO3Language());
-        // TODO: figure out how to handle failed to get language code.
-        if (command != null) {
-            sendCecCommand(command);
-        } else {
-            Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
-        }
-    }
-
-    private boolean dispatchMessageToAction(HdmiCecMessage message) {
-        for (FeatureAction action : mActions) {
-            if (action.processCommand(message)) {
-                return true;
-            }
-        }
-        Slog.w(TAG, "Unsupported cec command:" + message);
-        return false;
-    }
-
-    private void handleSetSystemAudioMode(HdmiCecMessage message) {
-        if (dispatchMessageToAction(message) || !isMessageForSystemAudio(message)) {
-            return;
-        }
-        SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
-                message.getDestination(), message.getSource(),
-                HdmiUtils.parseCommandParamSystemAudioStatus(message));
-        addAndStartAction(action);
-    }
-
-    private void handleSystemAudioModeStatus(HdmiCecMessage message) {
-        if (!isMessageForSystemAudio(message)) {
-            return;
-        }
-        setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
-    }
-
-    private boolean isMessageForSystemAudio(HdmiCecMessage message) {
-        if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM
-                || message.getDestination() != HdmiCec.ADDR_TV
-                || getAvrDeviceInfo() == null) {
-            Slog.w(TAG, "Skip abnormal CecMessage: " + message);
-            return false;
-        }
-        return true;
-    }
-
     // Record class that monitors the event of the caller of being killed. Used to clean up
     // the listener list and record list accordingly.
     private final class HotplugEventListenerRecord implements IBinder.DeathRecipient {
@@ -625,8 +467,20 @@
         }
     }
 
-    void addCecDevice(HdmiCecDeviceInfo info) {
-        mCecController.addDeviceInfo(info);
+    private final class DeviceEventListenerRecord implements IBinder.DeathRecipient {
+        private final IHdmiDeviceEventListener mListener;
+
+        public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+            public void binderDied() {
+            synchronized (mLock) {
+                mDeviceEventListenerRecords.remove(this);
+                mDeviceEventListeners.remove(mListener);
+            }
+        }
     }
 
     private void enforceAccessPermission() {
@@ -637,9 +491,29 @@
         @Override
         public int[] getSupportedTypes() {
             enforceAccessPermission();
-            synchronized (mLock) {
-                return mLocalDevices;
+            // mLocalDevices is an unmodifiable list - no lock necesary.
+            int[] localDevices = new int[mLocalDevices.size()];
+            for (int i = 0; i < localDevices.length; ++i) {
+                localDevices[i] = mLocalDevices.get(i);
             }
+            return localDevices;
+        }
+
+        @Override
+        public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecLocalDeviceTv tv = tv();
+                    if (tv == null) {
+                        Slog.w(TAG, "Local playback device not available");
+                        invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+                        return;
+                    }
+                    tv.deviceSelect(logicalAddress, callback);
+                }
+            });
         }
 
         @Override
@@ -685,53 +559,55 @@
                 }
             });
         }
+
+        @Override
+        public void addDeviceEventListener(final IHdmiDeviceEventListener listener) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                    public void run() {
+                    HdmiControlService.this.addDeviceEventListener(listener);
+                }
+            });
+        }
+
+        @Override
+        public void portSelect(int portId, IHdmiControlCallback callback) {
+            // TODO: Implement this
+        }
+
+        @Override
+        public void sendKeyEvent(int keyCode, boolean isPressed) {
+            // TODO: Implement this
+        }
+
+        @Override
+        public List<HdmiPortInfo> getPortInfo() {
+            enforceAccessPermission();
+            return mPortInfo;
+        }
     }
 
-    private void oneTouchPlay(IHdmiControlCallback callback) {
-        if (hasAction(OneTouchPlayAction.class)) {
-            Slog.w(TAG, "oneTouchPlay already in progress");
-            invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
-            return;
-        }
-        HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
+    private void oneTouchPlay(final IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        HdmiCecLocalDevicePlayback source = playback();
         if (source == null) {
             Slog.w(TAG, "Local playback device not available");
             invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
             return;
         }
-        // TODO: Consider the case of multiple TV sets. For now we always direct the command
-        //       to the primary one.
-        OneTouchPlayAction action = OneTouchPlayAction.create(this,
-                source.getDeviceInfo().getLogicalAddress(),
-                source.getDeviceInfo().getPhysicalAddress(), HdmiCec.ADDR_TV, callback);
-        if (action == null) {
-            Slog.w(TAG, "Cannot initiate oneTouchPlay");
-            invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
-            return;
-        }
-        addAndStartAction(action);
+        source.oneTouchPlay(callback);
     }
 
-    private void queryDisplayStatus(IHdmiControlCallback callback) {
-        if (hasAction(DevicePowerStatusAction.class)) {
-            Slog.w(TAG, "queryDisplayStatus already in progress");
-            invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
-            return;
-        }
-        HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
+    private void queryDisplayStatus(final IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        HdmiCecLocalDevicePlayback source = playback();
         if (source == null) {
             Slog.w(TAG, "Local playback device not available");
             invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
             return;
         }
-        DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
-                source.getDeviceInfo().getLogicalAddress(), HdmiCec.ADDR_TV, callback);
-        if (action == null) {
-            Slog.w(TAG, "Cannot initiate queryDisplayStatus");
-            invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
-            return;
-        }
-        addAndStartAction(action);
+        source.queryDisplayStatus(callback);
     }
 
     private void addHotplugEventListener(IHdmiHotplugEventListener listener) {
@@ -761,6 +637,19 @@
         }
     }
 
+    private void addDeviceEventListener(IHdmiDeviceEventListener listener) {
+        synchronized (mLock) {
+            for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) {
+                if (record.mListener.asBinder() == listener.asBinder()) {
+                    listener.asBinder().unlinkToDeath(record, 0);
+                    mDeviceEventListenerRecords.remove(record);
+                    break;
+                }
+            }
+            mHotplugEventListeners.remove(listener);
+        }
+    }
+
     private void invokeCallback(IHdmiControlCallback callback, int result) {
         try {
             callback.onComplete(result);
@@ -769,30 +658,34 @@
         }
     }
 
-    HdmiCecDeviceInfo getAvrDeviceInfo() {
-        return mCecController.getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM);
+    private void announceHotplugEvent(int portNo, boolean connected) {
+        HdmiHotplugEvent event = new HdmiHotplugEvent(portNo, connected);
+        synchronized (mLock) {
+            for (IHdmiHotplugEventListener listener : mHotplugEventListeners) {
+                invokeHotplugEventListener(listener, event);
+            }
+        }
     }
 
-    void setAudioStatus(boolean mute, int volume) {
-        // TODO: Hook up with AudioManager.
+    private void invokeHotplugEventListener(IHdmiHotplugEventListener listener,
+            HdmiHotplugEvent event) {
+        try {
+            listener.onReceived(event);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e);
+        }
     }
 
-    boolean isInPresetInstallationMode() {
-        // TODO: Implement this.
-        return false;
+    private static boolean hasSameTopPort(int path1, int path2) {
+        return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK)
+                == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK);
     }
 
-    /**
-     * Called when a device is removed or removal of device is detected.
-     *
-     * @param address a logical address of a device to be removed
-     */
-    void removeCecDevice(int address) {
-        mCecController.removeDeviceInfo(address);
-        mCecMessageCache.flushMessagesFrom(address);
+    private HdmiCecLocalDeviceTv tv() {
+        return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV);
     }
 
-    HdmiCecMessageCache getCecMessageCache() {
-        return mCecMessageCache;
+    private HdmiCecLocalDevicePlayback playback() {
+        return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index ef128ed1..9b7cc8d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -19,6 +19,11 @@
 import android.hardware.hdmi.HdmiCec;
 import android.hardware.hdmi.HdmiCecMessage;
 import android.util.Slog;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Various utilities to handle HDMI CEC messages.
@@ -71,4 +76,49 @@
         return cmd.getParams().length > 0
                 && cmd.getParams()[0] == HdmiConstants.SYSTEM_AUDIO_STATUS_ON;
     }
+
+    /**
+     * Convert integer array to list of {@link Integer}.
+     *
+     * <p>The result is immutable.
+     *
+     * @param is integer array
+     * @return {@link List} instance containing the elements in the given array
+     */
+    static List<Integer> asImmutableList(final int[] is) {
+        ArrayList<Integer> list = new ArrayList<>(is.length);
+        for (int type : is) {
+            list.add(type);
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /**
+     * Assemble two bytes into single integer value.
+     *
+     * @param data to be assembled
+     * @return assembled value
+     */
+    static int twoBytesToInt(byte[] data) {
+        return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
+    }
+
+    /**
+     * Assemble three bytes into single integer value.
+     *
+     * @param data to be assembled
+     * @return assembled value
+     */
+    static int threeBytesToInt(byte[] data) {
+        return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
+    }
+
+    static <T> List<T> sparseArrayToList(SparseArray<T> array) {
+        ArrayList<T> list = new ArrayList<>();
+        for (int i = 0; i < array.size(); ++i) {
+            list.add(array.valueAt(i));
+        }
+        return list;
+    }
+
 }
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index c7a813d..647cc88 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -52,11 +52,10 @@
     /**
      * Constructor
      *
-     * @param service instance of {@link HdmiControlService}
-     * @param sourceAddress logical address of a device that initiate this action
+     * @param source {@link HdmiCecLocalDevice} instance
      */
-    HotplugDetectionAction(HdmiControlService service, int sourceAddress) {
-        super(service, sourceAddress);
+    HotplugDetectionAction(HdmiCecLocalDevice source) {
+        super(source);
     }
 
     @Override
@@ -90,13 +89,27 @@
         }
     }
 
+    /**
+     * Start device polling immediately.
+     */
+    void pollAllDevicesNow() {
+        // Clear existing timer to avoid overlapped execution
+        mActionTimer.clearTimerMessage();
+
+        mTimeoutCount = 0;
+        mState = STATE_WAIT_FOR_NEXT_POLLING;
+        pollAllDevices();
+
+        addTimer(mState, POLLING_INTERVAL_MS);
+    }
+
     // This method is called every 5 seconds.
     private void pollDevices() {
         // All device check called every 15 seconds.
         if (mTimeoutCount == 0) {
             pollAllDevices();
         } else {
-            if (mService.getSystemAudioMode()) {
+            if (tv().getSystemAudioMode()) {
                 pollAudioSystem();
             }
         }
@@ -107,29 +120,29 @@
     private void pollAllDevices() {
         Slog.v(TAG, "Poll all devices.");
 
-        mService.pollDevices(new DevicePollingCallback() {
+        pollDevices(new DevicePollingCallback() {
             @Override
             public void onPollingFinished(List<Integer> ackedAddress) {
                 checkHotplug(ackedAddress, false);
             }
-        }, HdmiControlService.POLL_ITERATION_IN_ORDER
-                | HdmiControlService.POLL_STRATEGY_REMOTES_DEVICES, POLL_RETRY_COUNT);
+        }, HdmiConstants.POLL_ITERATION_IN_ORDER
+                | HdmiConstants.POLL_STRATEGY_REMOTES_DEVICES, POLL_RETRY_COUNT);
     }
 
     private void pollAudioSystem() {
         Slog.v(TAG, "Poll audio system.");
 
-        mService.pollDevices(new DevicePollingCallback() {
+        pollDevices(new DevicePollingCallback() {
             @Override
             public void onPollingFinished(List<Integer> ackedAddress) {
                 checkHotplug(ackedAddress, true);
             }
-        }, HdmiControlService.POLL_ITERATION_IN_ORDER
-                | HdmiControlService.POLL_STRATEGY_SYSTEM_AUDIO, POLL_RETRY_COUNT);
+        }, HdmiConstants.POLL_ITERATION_IN_ORDER
+                | HdmiConstants.POLL_STRATEGY_SYSTEM_AUDIO, POLL_RETRY_COUNT);
     }
 
     private void checkHotplug(List<Integer> ackedAddress, boolean audioOnly) {
-        BitSet currentInfos = infoListToBitSet(mService.getDeviceInfoList(false), audioOnly);
+        BitSet currentInfos = infoListToBitSet(tv().getDeviceInfoList(false), audioOnly);
         BitSet polledResult = addressListToBitSet(ackedAddress);
 
         // At first, check removed devices.
@@ -180,15 +193,55 @@
     }
 
     private void addDevice(int addedAddress) {
-        // TODO: implement this.
+        // Send <Give Physical Address>.
+        sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(),
+                addedAddress));
     }
 
     private void removeDevice(int removedAddress) {
-        mService.removeCecDevice(removedAddress);
-        // TODO: implements following steps.
-        // 1. Launch routing control sequence
-        // 2. Stop one touch play sequence if removed device is the device to be selected.
-        // 3. If audio system, start system audio off and arc off
-        // 4. Inform device remove to others
+        // TODO: move the following logic to local device once move many logic to
+        //       local device.
+        mayChangeRoutingPath(removedAddress);
+        mayCancelDeviceSelect(removedAddress);
+        mayCancelOneTouchRecord(removedAddress);
+        mayDisableSystemAudioAndARC(removedAddress);
+
+        tv().removeCecDevice(removedAddress);
+    }
+
+    private void mayChangeRoutingPath(int address) {
+        // TODO: if removed address is current active source, it should change active source
+        // path new one. we can keep previous selection or can choose default input,
+        // such as internal tuner. Consider send intent to app so that app
+        // can handle it.
+    }
+
+    private void mayCancelDeviceSelect(int address) {
+        List<DeviceSelectAction> actions = getActions(DeviceSelectAction.class);
+        if (actions.isEmpty()) {
+            return;
+        }
+
+        // Should ave only one Device Select Action
+        DeviceSelectAction action = actions.get(0);
+        if (action.getTargetAddress() == address) {
+            removeAction(DeviceSelectAction.class);
+        }
+    }
+
+    private void mayCancelOneTouchRecord(int address) {
+        // TODO: implement this.
+    }
+
+    private void mayDisableSystemAudioAndARC(int address) {
+        if (HdmiCec.getTypeFromAddress(address) != HdmiCec.DEVICE_AUDIO_SYSTEM) {
+            return;
+        }
+
+        // Turn off system audio mode.
+        tv().setSystemAudioMode(false);
+        if (tv().getArcStatus()) {
+            addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
+        }
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 088c40b..4a49f09 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -48,6 +48,7 @@
 
     private final int mDeviceLogicalAddress;
     private final int mDevicePhysicalAddress;
+    private final boolean mRequireRoutingChange;
 
     private int mVendorId;
     private String mDisplayName;
@@ -55,27 +56,45 @@
     /**
      * Constructor.
      *
-     * @param service {@link HdmiControlService} instance
-     * @param sourceAddress logical address to be used as source address
+     * @param source {@link HdmiCecLocalDevice} instance
      * @param deviceLogicalAddress logical address of the device in interest
      * @param devicePhysicalAddress physical address of the device in interest
+     * @param requireRoutingChange whether to initiate routing change or not
      */
-    NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress,
-            int devicePhysicalAddress) {
-        super(service, sourceAddress);
+    NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress,
+            int devicePhysicalAddress, boolean requireRoutingChange) {
+        super(source);
         mDeviceLogicalAddress = deviceLogicalAddress;
         mDevicePhysicalAddress = devicePhysicalAddress;
         mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
+        mRequireRoutingChange = requireRoutingChange;
     }
 
     @Override
     public boolean start() {
+        if (HdmiCec.getTypeFromAddress(getSourceAddress()) == HdmiCec.DEVICE_AUDIO_SYSTEM) {
+            if (tv().getAvrDeviceInfo() == null) {
+                // TODO: Start system audio initiation action
+            }
+
+            // If new device is connected through ARC enabled port,
+            // initiates ARC channel establishment.
+            if (tv().isConnectedToArcPort(mDevicePhysicalAddress)) {
+                addAndStartAction(new RequestArcInitiationAction(localDevice(),
+                                mDeviceLogicalAddress));
+            }
+        }
+
+        if (mRequireRoutingChange) {
+            startRoutingChange();
+        }
+
         mState = STATE_WAITING_FOR_SET_OSD_NAME;
         if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_SET_OSD_NAME)) {
             return true;
         }
 
-        sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress,
+        sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(),
                 mDeviceLogicalAddress));
         addTimer(mState, TIMEOUT_MS);
         return true;
@@ -114,8 +133,7 @@
         } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
             if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
                 if (params.length == 3) {
-                    mVendorId = ((params[0] & 0xFF) << 16) + ((params[1] & 0xFF) << 8)
-                        + (params[2] & 0xFF);
+                    mVendorId = HdmiUtils.threeBytesToInt(params);
                 } else {
                     Slog.e(TAG, "Failed to get device vendor ID: ");
                 }
@@ -134,8 +152,24 @@
         return false;
     }
 
+    private void startRoutingChange() {
+        // Stop existing routing control.
+        removeAction(RoutingControlAction.class);
+
+        // Send routing change. The the address is a path of the active port.
+        int newPath = toTopMostPortPath(mDevicePhysicalAddress);
+        sendCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
+                localDevice().getActivePath(), newPath));
+        addAndStartAction(new RoutingControlAction(localDevice(),
+                localDevice().pathToPortId(newPath), null));
+    }
+
+    private static int toTopMostPortPath(int physicalAddress) {
+        return physicalAddress & HdmiConstants.ROUTING_PATH_TOP_MASK;
+    }
+
     private boolean mayProcessCommandIfCached(int destAddress, int opcode) {
-        HdmiCecMessage message = mService.getCecMessageCache().getMessage(destAddress, opcode);
+        HdmiCecMessage message = getCecMessageCache().getMessage(destAddress, opcode);
         if (message != null) {
             return processCommand(message);
         }
@@ -149,7 +183,7 @@
         if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) {
             return;
         }
-        sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress,
+        sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(),
                 mDeviceLogicalAddress));
         addTimer(mState, TIMEOUT_MS);
     }
@@ -158,7 +192,7 @@
         if (mDisplayName == null) {
             mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress);
         }
-        mService.addCecDevice(new HdmiCecDeviceInfo(
+        tv().addCecDevice(new HdmiCecDeviceInfo(
                 mDeviceLogicalAddress, mDevicePhysicalAddress,
                 HdmiCec.getTypeFromAddress(mDeviceLogicalAddress),
                 mVendorId, mDisplayName));
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 69fad13..e0a3a8b 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -30,7 +30,7 @@
  * <p>Package-private, accessed by {@link HdmiControlService} only.
  */
 
-public final class OneTouchPlayAction extends FeatureAction {
+final class OneTouchPlayAction extends FeatureAction {
     private static final String TAG = "OneTouchPlayAction";
 
     // State in which the action is waiting for <Report Power Status>. In normal situation
@@ -48,34 +48,32 @@
     // We wait up to RESPONSE_TIMEOUT_MS * LOOP_COUNTER_MAX = 20 seconds.
     private static final int LOOP_COUNTER_MAX = 10;
 
-    private final int mSourcePath;
     private final int mTargetAddress;
     private final IHdmiControlCallback mCallback;
 
     private int mPowerStatusCounter = 0;
 
     // Factory method. Ensures arguments are valid.
-    static OneTouchPlayAction create(HdmiControlService service, int sourceAddress,
-            int sourcePath, int targetAddress, IHdmiControlCallback callback) {
-        if (service == null || callback == null) {
+    static OneTouchPlayAction create(HdmiCecLocalDevice source,
+            int targetAddress, IHdmiControlCallback callback) {
+        if (source == null || callback == null) {
             Slog.e(TAG, "Wrong arguments");
             return null;
         }
-        return new OneTouchPlayAction(service, sourceAddress, sourcePath, targetAddress, callback);
+        return new OneTouchPlayAction(source, targetAddress,
+                callback);
     }
 
-    private OneTouchPlayAction(HdmiControlService service, int sourceAddress, int sourcePath,
-            int targetAddress, IHdmiControlCallback callback) {
-        super(service, sourceAddress);
-        mSourcePath = sourcePath;
+    private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
+            IHdmiControlCallback callback) {
+        super(localDevice);
         mTargetAddress = targetAddress;
         mCallback = callback;
     }
 
     @Override
     boolean start() {
-        mService.sendCecCommand(
-                HdmiCecMessageBuilder.buildTextViewOn(mSourceAddress, mTargetAddress));
+        sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress));
         broadcastActiveSource();
         queryDevicePowerStatus();
         mState = STATE_WAITING_FOR_REPORT_POWER_STATUS;
@@ -84,13 +82,12 @@
     }
 
     private void broadcastActiveSource() {
-        mService.sendCecCommand(
-                HdmiCecMessageBuilder.buildActiveSource(mSourceAddress, mSourcePath));
+        sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath()));
     }
 
     private void queryDevicePowerStatus() {
-        mService.sendCecCommand(
-                HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, mTargetAddress));
+        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
+                mTargetAddress));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index 08ca306..a2e08f1 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -35,16 +35,14 @@
     /**
      * @Constructor
      *
-     * @param service {@link HdmiControlService} instance
-     * @param sourceAddress logical address to be used as source address. It should
-     *                      TV type
+     * @param source {@link HdmiCecLocalDevice} instance
      * @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type
      * @throw IllegalArugmentException if device type of sourceAddress and avrAddress
      *                      is invalid
      */
-    RequestArcAction(HdmiControlService service, int sourceAddress, int avrAddress) {
-        super(service, sourceAddress);
-        HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
+    RequestArcAction(HdmiCecLocalDevice source, int avrAddress) {
+        super(source);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
         HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
         mAvrAddress = avrAddress;
     }
@@ -72,9 +70,9 @@
 
     protected final void disableArcTransmission() {
         // Start Set ARC Transmission State action.
-        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(mService,
-                mSourceAddress, mAvrAddress, false);
-        mService.addAndStartAction(action);
+        SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(localDevice(),
+                mAvrAddress, false);
+        addAndStartAction(action);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index 343aff7..55fb65a 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -31,18 +31,18 @@
      *
      * For more details look at {@link RequestArcAction#RequestArcAction}.
      */
-    RequestArcInitiationAction(HdmiControlService service, int sourceAddress, int avrAddress) {
-        super(service, sourceAddress, avrAddress);
+    RequestArcInitiationAction(HdmiCecLocalDevice source, int avrAddress) {
+        super(source, avrAddress);
     }
 
     @Override
     boolean start() {
-        HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress,
-                mAvrAddress);
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(
+                getSourceAddress(), mAvrAddress);
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
                     mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
                     addTimer(mState, TIMEOUT_MS);
                 } else {
diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
index d4a35f8..62ca8f6 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
@@ -31,18 +31,18 @@
      *
      * @see RequestArcAction#RequestArcAction
      */
-    RequestArcTerminationAction(HdmiControlService service, int sourceAddress, int avrAddress) {
-        super(service, sourceAddress, avrAddress);
+    RequestArcTerminationAction(HdmiCecLocalDevice source, int avrAddress) {
+        super(source, avrAddress);
     }
 
     @Override
     boolean start() {
         HdmiCecMessage command =
-                HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress);
+                HdmiCecMessageBuilder.buildRequestArcTermination(getSourceAddress(), mAvrAddress);
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
                     mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
                     addTimer(mState, TIMEOUT_MS);
                 } else {
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
new file mode 100644
index 0000000..2eec846
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.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 com.android.server.hdmi;
+
+import android.annotation.Nullable;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * Feature action for routing control. Exchanges routing-related commands with other devices
+ * to determine the new active source.
+ *
+ * <p>This action is initiated by various cases:
+ * <ul>
+ * <li> Manual TV input switching
+ * <li> Routing change of a CEC switch other than TV
+ * <li> New CEC device at the tail of the active routing path
+ * <li> Removed CEC device from the active routing path
+ * <li> Routing at CEC enable time
+ * </ul>
+ */
+final class RoutingControlAction extends FeatureAction {
+    private static final String TAG = "RoutingControlAction";
+
+    // State in which we wait for <Routing Information> to arrive. If timed out, we use the
+    // latest routing path to set the new active source.
+    private final static int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
+
+    // State in which we wait for <Report Power Status> in response to <Give Device Power Status>
+    // we have sent. If the response tells us the device power is on, we send <Set Stream Path>
+    // to make it the active source. Otherwise we do not send <Set Stream Path>, and possibly
+    // just show the blank screen.
+    private final static int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2;
+
+    // Time out in millseconds used for <Routing Information>
+    private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
+
+    // Time out in milliseconds used for <Report Power Status>
+    private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000;
+
+    @Nullable private final IHdmiControlCallback mCallback;
+
+    // The latest routing path. Updated by each <Routing Information> from CEC switches.
+    private int mCurrentRoutingPath;
+
+    RoutingControlAction(HdmiCecLocalDevice localDevice, int path, IHdmiControlCallback callback) {
+        super(localDevice);
+        mCallback = callback;
+        mCurrentRoutingPath = path;
+    }
+
+    @Override
+    public boolean start() {
+        mState = STATE_WAIT_FOR_ROUTING_INFORMATION;
+        addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
+        return true;
+    }
+
+    @Override
+    public boolean processCommand(HdmiCecMessage cmd) {
+        int opcode = cmd.getOpcode();
+        byte[] params = cmd.getParams();
+        if (mState == STATE_WAIT_FOR_ROUTING_INFORMATION
+                && opcode == HdmiCec.MESSAGE_ROUTING_INFORMATION) {
+            // Keep updating the physicalAddress as we receive <Routing Information>.
+            // If the routing path doesn't belong to the currently active one, we should
+            // ignore it since it might have come from other routing change sequence.
+            int routingPath = HdmiUtils.twoBytesToInt(params);
+            if (isInActiveRoutingPath(mCurrentRoutingPath, routingPath)) {
+                return true;
+            }
+            mCurrentRoutingPath = routingPath;
+            // Stop possible previous routing change sequence if in progress.
+            removeAction(RoutingControlAction.class);
+            addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
+            return true;
+        } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
+                  && opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
+            handleReportPowerStatus(cmd.getParams()[0]);
+            return true;
+        }
+        return false;
+    }
+
+    private void handleReportPowerStatus(int devicePowerStatus) {
+        int tvPowerStatus = getTvPowerStatus();
+        if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
+            if (isPowerStatusOnOrTransientToOn(devicePowerStatus)) {
+                sendSetStreamPath();
+            } else {
+                // The whole action should be stopped here if the device is in standby mode.
+                // We don't attempt to wake it up by sending <Set Stream Path>.
+            }
+            invokeCallback(HdmiCec.RESULT_SUCCESS);
+            finish();
+          } else {
+              // TV is going into standby mode.
+              // TODO: Figure out what to do.
+          }
+     }
+
+    private int getTvPowerStatus() {
+        // TODO: Obtain TV power status.
+        return HdmiCec.POWER_STATUS_ON;
+    }
+
+    private static boolean isPowerStatusOnOrTransientToOn(int status) {
+        return status == HdmiCec.POWER_STATUS_ON || status == HdmiCec.POWER_STATUS_TRANSIENT_TO_ON;
+    }
+
+    private void sendSetStreamPath() {
+        sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(),
+                mCurrentRoutingPath));
+    }
+
+    private static boolean isInActiveRoutingPath(int activePath, int newPath) {
+        // Check each nibble of the currently active path and the new path till the position
+        // where the active nibble is not zero. For (activePath, newPath),
+        // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
+        // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
+        // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
+        // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
+        for (int i = 12; i >= 0; i -= 4) {
+            int nibbleActive = (activePath >> i) & 0xF;
+            if (nibbleActive == 0) {
+                break;
+            }
+            int nibbleNew = (newPath >> i) & 0xF;
+            if (nibbleNew == 0) {
+                break;
+            }
+            if (nibbleActive != nibbleNew) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void handleTimerEvent(int timeoutState) {
+        if (mState != timeoutState || mState == STATE_NONE) {
+            Slog.w("CEC", "Timer in a wrong state. Ignored.");
+            return;
+        }
+        switch (timeoutState) {
+            case STATE_WAIT_FOR_ROUTING_INFORMATION:
+                HdmiCecDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath);
+                if (device == null) {
+                    maybeChangeActiveInput(tv().pathToPortId(mCurrentRoutingPath));
+                } else {
+                    // TODO: Also check followings and then proceed:
+                    //       if routing change was neither triggered by TV at CEC enable time, nor
+                    //       at the detection of new device at the end of the active routing path, nor
+                    //       by TV power on with HDMI input as the active signal source.
+                    int deviceLogicalAddress = device.getLogicalAddress();
+                    queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() {
+                        @Override
+                        public void onSendCompleted(int error) {
+                            handlDevicePowerStatusAckResult(error == HdmiCec.RESULT_SUCCESS);
+                        }
+                    });
+                }
+                return;
+            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+                int tvPowerStatus = getTvPowerStatus();
+                if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
+                    if (!maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath))) {
+                        sendSetStreamPath();
+                    }
+                }
+                invokeCallback(HdmiCec.RESULT_SUCCESS);
+                finish();
+                return;
+        }
+    }
+
+    // Called whenever an HDMI input of the TV shall become the active input.
+    private boolean maybeChangeActiveInput(int path) {
+        if (localDevice().getActiveInput() == localDevice().pathToPortId(path)) {
+            return false;
+        }
+        // TODO: Remember the currently active input
+        //       if PAP/PIP is active, move the focus to the right window, otherwise switch
+        //       the port.
+        //       Show the OSD input change banner.
+        return true;
+    }
+
+    private void queryDevicePowerStatus(int address, SendMessageCallback callback) {
+        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address),
+                callback);
+    }
+
+    private void handlDevicePowerStatusAckResult(boolean acked) {
+        if (acked) {
+            mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+            addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
+        } else {
+            maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath));
+        }
+    }
+
+    private void invokeCallback(int result) {
+        if (mCallback == null) {
+            return;
+        }
+        try {
+            mCallback.onComplete(result);
+        } catch (RemoteException e) {
+            // Do nothing.
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index 5eb9315..c3078a2 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -16,10 +16,8 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCecMessage;
-import android.view.KeyEvent;
 import android.util.Slog;
-
-import libcore.util.EmptyArray;
+import android.view.KeyEvent;
 
 /**
  * Feature action that transmits remote control key command (User Control Press/
@@ -56,13 +54,12 @@
     /**
      * Constructor.
      *
-     * @param service {@link HdmiControlService} instance
-     * @param sourceAddress logical address to be used as source address
+     * @param source {@link HdmiCecLocalDevice} instance
      * @param targetAddress logical address of the device to send the keys to
      * @param keyCode remote control key code as defined in {@link KeyEvent}
      */
-    SendKeyAction(HdmiControlService service, int sourceAddress, int targetAddress, int keyCode) {
-        super(service, sourceAddress);
+    SendKeyAction(HdmiCecLocalDevice source, int targetAddress, int keyCode) {
+        super(source);
         mTargetAddress = targetAddress;
         mLastKeyCode = keyCode;
     }
@@ -112,12 +109,13 @@
         if (keyCodeAndParam == null) {
             return;
         }
-        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(mSourceAddress, mTargetAddress,
-                keyCodeAndParam));
+        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
+                mTargetAddress, keyCodeAndParam));
     }
 
     private void sendKeyUp() {
-        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(mSourceAddress, mTargetAddress));
+        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
+                mTargetAddress));
     }
 
     @Override
@@ -146,8 +144,6 @@
     // KeyEvent.KEYCODE_TV_BROADCAST_CABLE.
     // The return byte array contains both UI command (keycode) and optional parameter.
     private byte[] getCecKeyCodeAndParam(int keyCode) {
-        // TODO: Convert to CEC keycode and (optionally) parameter.
-        //       return androidKeyToCecKey(keyCode);
-        return EmptyArray.BYTE;
+        return HdmiCecKeycode.androidKeyToCecKey(keyCode);
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index d53d88d..cdedd6b 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -39,14 +39,13 @@
     /**
      * @Constructor
      *
-     * @param service an instance of {@link HdmiControlService}
-     * @param sourceAddress logical address to be used as source address
+     * @param source {@link HdmiCecLocalDevice} instance
      * @param enabled whether to enable ARC Transmission channel
      */
-    SetArcTransmissionStateAction(HdmiControlService service, int sourceAddress, int avrAddress,
+    SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress,
             boolean enabled) {
-        super(service, sourceAddress);
-        HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
+        super(source);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
         HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
         mAvrAddress = avrAddress;
         mEnabled = enabled;
@@ -65,11 +64,11 @@
 
     private void sendReportArcInitiated() {
         HdmiCecMessage command =
-                HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress);
+                HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress);
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
                     // Enable ARC status immediately after sending <Report Arc Initiated>.
                     // If AVR responds with <Feature Abort>, disable ARC status again.
                     // This is different from spec that says that turns ARC status to
@@ -93,14 +92,14 @@
     }
 
     private void setArcStatus(boolean enabled) {
-        boolean wasEnabled = mService.setArcStatus(enabled);
+        boolean wasEnabled = tv().setArcStatus(enabled);
         Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled);
 
         // If enabled before and set to "disabled" and send <Report Arc Terminated> to
         // av reciever.
         if (!enabled && wasEnabled) {
-            sendCommand(
-                    HdmiCecMessageBuilder.buildReportArcTerminated(mSourceAddress, mAvrAddress));
+            sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
+                    mAvrAddress));
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index dde3342..e48b0dc 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -47,28 +47,27 @@
     /**
      * Constructor
      *
-     * @param service {@link HdmiControlService} instance
-     * @param sourceAddress logical address of source device (TV or STB).
+     * @param source {@link HdmiCecLocalDevice} instance
      * @param avrAddress logical address of AVR device
      * @param targetStatus Whether to enable the system audio mode or not
      * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
      */
-    SystemAudioAction(HdmiControlService service, int sourceAddress, int avrAddress,
-            boolean targetStatus) {
-        super(service, sourceAddress);
+    SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) {
+        super(source);
         HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
         mAvrLogicalAddress = avrAddress;
         mTargetAudioStatus = targetStatus;
     }
 
     protected void sendSystemAudioModeRequest() {
-        int avrPhysicalAddress = mService.getAvrDeviceInfo().getPhysicalAddress();
-        HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(mSourceAddress,
+        int avrPhysicalAddress = tv().getAvrDeviceInfo().getPhysicalAddress();
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+                getSourceAddress(),
                 mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus);
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
                     mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
                     addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
                 } else {
@@ -90,16 +89,16 @@
     }
 
     protected void setSystemAudioMode(boolean mode) {
-        mService.setSystemAudioMode(mode);
+        tv().setSystemAudioMode(mode);
     }
 
     protected void sendGiveAudioStatus() {
-        HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(mSourceAddress,
+        HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(),
                 mAvrLogicalAddress);
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
                     mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
                     addTimer(mState, TIMEOUT_MS);
                 } else {
@@ -112,7 +111,7 @@
     private void handleSendGiveAudioStatusFailure() {
         // TODO: Notify the failure status.
 
-        int uiCommand = mService.getSystemAudioMode()
+        int uiCommand = tv().getSystemAudioMode()
                 ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
                 : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
         sendUserControlPressedAndReleased(uiCommand);
@@ -121,9 +120,9 @@
 
     private void sendUserControlPressedAndReleased(int uiCommand) {
         sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
-                mSourceAddress, mAvrLogicalAddress, uiCommand));
+                getSourceAddress(), mAvrLogicalAddress, uiCommand));
         sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
-                mSourceAddress, mAvrLogicalAddress));
+                getSourceAddress(), mAvrLogicalAddress));
     }
 
     @Override
@@ -158,7 +157,7 @@
                 if (params.length > 0) {
                     boolean mute = (params[0] & 0x80) == 0x80;
                     int volume = params[0] & 0x7F;
-                    mService.setAudioStatus(mute, volume);
+                    tv().setAudioStatus(mute, volume);
                     if (mTargetAudioStatus && mute || !mTargetAudioStatus && !mute) {
                         // Toggle AVR's mute status to match with the system audio status.
                         sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
@@ -171,8 +170,8 @@
     }
 
     protected void removeSystemAudioActionInProgress() {
-        mService.removeActionExcept(SystemAudioActionFromTv.class, this);
-        mService.removeActionExcept(SystemAudioActionFromAvr.class, this);
+        removeActionExcept(SystemAudioActionFromTv.class, this);
+        removeActionExcept(SystemAudioActionFromAvr.class, this);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
index c5eb44b..3907b71 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
@@ -25,16 +25,15 @@
     /**
      * Constructor
      *
-     * @param service {@link HdmiControlService} instance
-     * @param tvAddress logical address of TV device
+     * @param source {@link HdmiCecLocalDevice} instance
      * @param avrAddress logical address of AVR device
      * @param targetStatus Whether to enable the system audio mode or not
      * @throw IllegalArugmentException if device type of tvAddress and avrAddress is invalid
      */
-    SystemAudioActionFromAvr(HdmiControlService service, int tvAddress, int avrAddress,
+    SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress,
             boolean targetStatus) {
-        super(service, tvAddress, avrAddress, targetStatus);
-        HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV);
+        super(source, avrAddress, targetStatus);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
     }
 
     @Override
@@ -45,13 +44,13 @@
     }
 
     private void handleSystemAudioActionFromAvr() {
-        if (mTargetAudioStatus == mService.getSystemAudioMode()) {
+        if (mTargetAudioStatus == tv().getSystemAudioMode()) {
             finish();
             return;
         }
-        if (mService.isInPresetInstallationMode()) {
+        if (tv().isInPresetInstallationMode()) {
             sendCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(
-                    mSourceAddress, mAvrLogicalAddress,
+                    getSourceAddress(), mAvrLogicalAddress,
                     HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE, HdmiConstants.ABORT_REFUSED));
             mTargetAudioStatus = false;
             sendSystemAudioModeRequest();
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
index 9994de6..e0c4ff4 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
@@ -26,16 +26,15 @@
     /**
      * Constructor
      *
-     * @param service {@link HdmiControlService} instance
-     * @param tvAddress logical address of TV device
+     * @param sourceAddress {@link HdmiCecLocalDevice} instance
      * @param avrAddress logical address of AVR device
      * @param targetStatus Whether to enable the system audio mode or not
      * @throw IllegalArugmentException if device type of tvAddress is invalid
      */
-    SystemAudioActionFromTv(HdmiControlService service, int tvAddress, int avrAddress,
+    SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress,
             boolean targetStatus) {
-        super(service, tvAddress, avrAddress, targetStatus);
-        HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV);
+        super(sourceAddress, avrAddress, targetStatus);
+        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/hdmi/VendorSpecificAction.java b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java
new file mode 100644
index 0000000..c954b50
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java
@@ -0,0 +1,54 @@
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+
+/**
+ * Handles vendor-specific commands that require a sequence of command exchange,
+ * or need to manage some states to complete the processing.
+ */
+public class VendorSpecificAction extends FeatureAction {
+
+    // Sample state this action can be in.
+    private static final int STATE_1 = 1;
+    private static final int STATE_2 = 2;
+
+    VendorSpecificAction(HdmiCecLocalDevice source) {
+        super(source);
+        // Modify the constructor if additional arguments are necessary.
+    }
+
+    @Override
+    boolean start() {
+        // Do initialization step and update the state accordingly here.
+        mState = STATE_1;
+        addTimer(STATE_1, TIMEOUT_MS);
+        return true;
+    }
+
+    @Override
+    boolean processCommand(HdmiCecMessage cmd) {
+        // Returns true if the command was consumed. Otherwise return false for other
+        // actions in progress can be given its turn to process it.
+        return false;
+    }
+
+    @Override
+    void handleTimerEvent(int state) {
+        // Ignore the timer event if the current state and the state this event should be
+        // handled in are different. Could be an outdated event which should have been cleared by
+        // calling {@code mActionTimer.clearTimerMessage()}.
+        if (mState != state) {
+            return;
+        }
+
+        switch (state) {
+            case STATE_1:
+                mState = STATE_2;
+                addTimer(STATE_2, TIMEOUT_MS);
+                break;
+            case STATE_2:
+                finish();
+                break;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/job/JobCompletedListener.java
similarity index 62%
rename from services/core/java/com/android/server/task/TaskCompletedListener.java
rename to services/core/java/com/android/server/job/JobCompletedListener.java
index c53f5ca..a7af9cd 100644
--- a/services/core/java/com/android/server/task/TaskCompletedListener.java
+++ b/services/core/java/com/android/server/job/JobCompletedListener.java
@@ -14,19 +14,19 @@
  * limitations under the License
  */
 
-package com.android.server.task;
+package com.android.server.job;
 
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
 
 /**
- * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
- * {@link com.android.server.task.TaskManagerService}.
+ * Used for communication between {@link com.android.server.job.JobServiceContext} and the
+ * {@link com.android.server.job.JobSchedulerService}.
  */
-public interface TaskCompletedListener {
+public interface JobCompletedListener {
 
     /**
-     * Callback for when a task is completed.
-     * @param needsReschedule Whether the implementing class should reschedule this task.
+     * Callback for when a job is completed.
+     * @param needsReschedule Whether the implementing class should reschedule this job.
      */
-    public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule);
+    public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule);
 }
diff --git a/services/core/java/com/android/server/task/TaskMapReadFinishedListener.java b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
similarity index 68%
rename from services/core/java/com/android/server/task/TaskMapReadFinishedListener.java
rename to services/core/java/com/android/server/job/JobMapReadFinishedListener.java
index c68d8db..f3e77e6 100644
--- a/services/core/java/com/android/server/task/TaskMapReadFinishedListener.java
+++ b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
@@ -14,21 +14,21 @@
  * limitations under the License
  */
 
-package com.android.server.task;
+package com.android.server.job;
 
 import java.util.List;
 
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
 
 /**
- * Callback definition for I/O thread to let the TaskManagerService know when
+ * Callback definition for I/O thread to let the JobManagerService know when
  * I/O read has completed. Done this way so we don't stall the main thread on
  * boot.
  */
-public interface TaskMapReadFinishedListener {
+public interface JobMapReadFinishedListener {
 
     /**
-     * Called by the {@link TaskStore} at boot, when the disk read is finished.
+     * Called by the {@link JobStore} at boot, when the disk read is finished.
      */
-    public void onTaskMapReadFinished(List<TaskStatus> tasks);
+    public void onJobMapReadFinished(List<JobStatus> jobs);
 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
new file mode 100644
index 0000000..0e9a9cc
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -0,0 +1,764 @@
+/*
+ * 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.job;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.app.job.IJobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.job.controllers.BatteryController;
+import com.android.server.job.controllers.ConnectivityController;
+import com.android.server.job.controllers.IdleController;
+import com.android.server.job.controllers.JobStatus;
+import com.android.server.job.controllers.StateController;
+import com.android.server.job.controllers.TimeController;
+
+import java.util.LinkedList;
+
+/**
+ * Responsible for taking jobs representing work to be performed by a client app, and determining
+ * based on the criteria specified when that job should be run against the client application's
+ * endpoint.
+ * Implements logic for scheduling, and rescheduling jobs. The JobSchedulerService knows nothing
+ * about constraints, or the state of active jobs. It receives callbacks from the various
+ * controllers and completed jobs and operates accordingly.
+ *
+ * Note on locking: Any operations that manipulate {@link #mJobs} need to lock on that object.
+ * Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
+ * @hide
+ */
+public class JobSchedulerService extends com.android.server.SystemService
+        implements StateChangedListener, JobCompletedListener, JobMapReadFinishedListener {
+    // TODO: Switch this off for final version.
+    static final boolean DEBUG = true;
+    /** The number of concurrent jobs we run at one time. */
+    private static final int MAX_JOB_CONTEXTS_COUNT = 3;
+    static final String TAG = "JobManagerService";
+    /** Master list of jobs. */
+    private final JobStore mJobs;
+
+    static final int MSG_JOB_EXPIRED = 0;
+    static final int MSG_CHECK_JOB = 1;
+
+    // Policy constants
+    /**
+     * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
+     * early.
+     */
+    private static final int MIN_IDLE_COUNT = 1;
+    /**
+     * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
+     * things early.
+     */
+    private static final int MIN_CONNECTIVITY_COUNT = 2;
+    /**
+     * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
+     * some work early.
+     */
+    private static final int MIN_READY_JOBS_COUNT = 4;
+
+    /**
+     * Track Services that have currently active or pending jobs. The index is provided by
+     * {@link JobStatus#getServiceToken()}
+     */
+    private final List<JobServiceContext> mActiveServices = new LinkedList<JobServiceContext>();
+    /** List of controllers that will notify this service of updates to jobs. */
+    private List<StateController> mControllers;
+    /**
+     * Queue of pending jobs. The JobServiceContext class will receive jobs from this list
+     * when ready to execute them.
+     */
+    private final LinkedList<JobStatus> mPendingJobs = new LinkedList<JobStatus>();
+
+    private final JobHandler mHandler;
+    private final JobSchedulerStub mJobSchedulerStub;
+    /**
+     * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
+     * still clean up. On reinstall the package will have a new uid.
+     */
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Slog.d(TAG, "Receieved: " + intent.getAction());
+            if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+                }
+                cancelJobsForUid(uidRemoved);
+            } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing jobs for user: " + userId);
+                }
+                cancelJobsForUser(userId);
+            }
+        }
+    };
+
+    /**
+     * Entry point from client to schedule the provided job.
+     * This cancels the job if it's already been scheduled, and replaces it with the one provided.
+     * @param job JobInfo object containing execution parameters
+     * @param uId The package identifier of the application this job is for.
+     * @param canPersistJob Whether or not the client has the appropriate permissions for
+     *                       persisting this job.
+     * @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
+     */
+    public int schedule(JobInfo job, int uId, boolean canPersistJob) {
+        JobStatus jobStatus = new JobStatus(job, uId, canPersistJob);
+        cancelJob(uId, job.getId());
+        startTrackingJob(jobStatus);
+        return JobScheduler.RESULT_SUCCESS;
+    }
+
+    public List<JobInfo> getPendingJobs(int uid) {
+        ArrayList<JobInfo> outList = new ArrayList<JobInfo>();
+        synchronized (mJobs) {
+            for (JobStatus job : mJobs.getJobs()) {
+                if (job.getUid() == uid) {
+                    outList.add(job.getJob());
+                }
+            }
+        }
+        return outList;
+    }
+
+    private void cancelJobsForUser(int userHandle) {
+        synchronized (mJobs) {
+            List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
+            for (JobStatus toRemove : jobsForUser) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Cancelling: " + toRemove);
+                }
+                cancelJobLocked(toRemove);
+            }
+        }
+    }
+
+    /**
+     * Entry point from client to cancel all jobs originating from their uid.
+     * This will remove the job from the master list, and cancel the job if it was staged for
+     * execution or being executed.
+     * @param uid To check against for removal of a job.
+     */
+    public void cancelJobsForUid(int uid) {
+        // Remove from master list.
+        synchronized (mJobs) {
+            List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
+            for (JobStatus toRemove : jobsForUid) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Cancelling: " + toRemove);
+                }
+                cancelJobLocked(toRemove);
+            }
+        }
+    }
+
+    /**
+     * Entry point from client to cancel the job corresponding to the jobId provided.
+     * This will remove the job from the master list, and cancel the job if it was staged for
+     * execution or being executed.
+     * @param uid Uid of the calling client.
+     * @param jobId Id of the job, provided at schedule-time.
+     */
+    public void cancelJob(int uid, int jobId) {
+        JobStatus toCancel;
+        synchronized (mJobs) {
+            toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
+            if (toCancel != null) {
+                cancelJobLocked(toCancel);
+            }
+        }
+    }
+
+    private void cancelJobLocked(JobStatus cancelled) {
+        // Remove from store.
+        stopTrackingJob(cancelled);
+        // Remove from pending queue.
+        mPendingJobs.remove(cancelled);
+        // Cancel if running.
+        stopJobOnServiceContextLocked(cancelled);
+    }
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public JobSchedulerService(Context context) {
+        super(context);
+        // Create the controllers.
+        mControllers = new LinkedList<StateController>();
+        mControllers.add(ConnectivityController.get(this));
+        mControllers.add(TimeController.get(this));
+        mControllers.add(IdleController.get(this));
+        mControllers.add(BatteryController.get(this));
+
+        mHandler = new JobHandler(context.getMainLooper());
+        mJobSchedulerStub = new JobSchedulerStub();
+        // Create the "runners".
+        for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+            mActiveServices.add(
+                    new JobServiceContext(this, context.getMainLooper()));
+        }
+        mJobs = JobStore.initAndGet(this);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (PHASE_SYSTEM_SERVICES_READY == phase) {
+            // Register br for package removals and user removals.
+            final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addDataScheme("package");
+            getContext().registerReceiverAsUser(
+                    mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+            final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+            getContext().registerReceiverAsUser(
+                    mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+        }
+    }
+
+    /**
+     * Called when we have a job status object that we need to insert in our
+     * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know
+     * about.
+     */
+    private void startTrackingJob(JobStatus jobStatus) {
+        boolean update;
+        synchronized (mJobs) {
+            update = mJobs.add(jobStatus);
+        }
+        for (StateController controller : mControllers) {
+            if (update) {
+                controller.maybeStopTrackingJob(jobStatus);
+            }
+            controller.maybeStartTrackingJob(jobStatus);
+        }
+    }
+
+    /**
+     * Called when we want to remove a JobStatus object that we've finished executing. Returns the
+     * object removed.
+     */
+    private boolean stopTrackingJob(JobStatus jobStatus) {
+        boolean removed;
+        synchronized (mJobs) {
+            // Remove from store as well as controllers.
+            removed = mJobs.remove(jobStatus);
+        }
+        if (removed) {
+            for (StateController controller : mControllers) {
+                controller.maybeStopTrackingJob(jobStatus);
+            }
+        }
+        return removed;
+    }
+
+    private boolean stopJobOnServiceContextLocked(JobStatus job) {
+        for (JobServiceContext jsc : mActiveServices) {
+            final JobStatus executing = jsc.getRunningJob();
+            if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+                jsc.cancelExecutingJob();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param job JobStatus we are querying against.
+     * @return Whether or not the job represented by the status object is currently being run or
+     * is pending.
+     */
+    private boolean isCurrentlyActiveLocked(JobStatus job) {
+        for (JobServiceContext serviceContext : mActiveServices) {
+            final JobStatus running = serviceContext.getRunningJob();
+            if (running != null && running.matches(job.getUid(), job.getJobId())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * A job is rescheduled with exponential back-off if the client requests this from their
+     * execution logic.
+     * A caveat is for idle-mode jobs, for which the idle-mode constraint will usurp the
+     * timeliness of the reschedule. For an idle-mode job, no deadline is given.
+     * @param failureToReschedule Provided job status that we will reschedule.
+     * @return A newly instantiated JobStatus with the same constraints as the last job except
+     * with adjusted timing constraints.
+     */
+    private JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
+        final long elapsedNowMillis = SystemClock.elapsedRealtime();
+        final JobInfo job = failureToReschedule.getJob();
+
+        final long initialBackoffMillis = job.getInitialBackoffMillis();
+        final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
+        long newEarliestRuntimeElapsed = elapsedNowMillis;
+
+        switch (job.getBackoffPolicy()) {
+            case JobInfo.BackoffPolicy.LINEAR:
+                newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
+                break;
+            default:
+                if (DEBUG) {
+                    Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
+                }
+            case JobInfo.BackoffPolicy.EXPONENTIAL:
+                newEarliestRuntimeElapsed +=
+                        Math.pow(initialBackoffMillis * 0.001, backoffAttempt) * 1000;
+                break;
+        }
+        newEarliestRuntimeElapsed =
+                Math.min(newEarliestRuntimeElapsed, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
+        return new JobStatus(failureToReschedule, newEarliestRuntimeElapsed,
+                JobStatus.NO_LATEST_RUNTIME, backoffAttempt);
+    }
+
+    /**
+     * Called after a periodic has executed so we can to re-add it. We take the last execution time
+     * of the job to be the time of completion (i.e. the time at which this function is called).
+     * This could be inaccurate b/c the job can run for as long as
+     * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
+     * to underscheduling at least, rather than if we had taken the last execution time to be the
+     * start of the execution.
+     * @return A new job representing the execution criteria for this instantiation of the
+     * recurring job.
+     */
+    private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
+        final long elapsedNow = SystemClock.elapsedRealtime();
+        // Compute how much of the period is remaining.
+        long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
+        long newEarliestRunTimeElapsed = elapsedNow + runEarly;
+        long period = periodicToReschedule.getJob().getIntervalMillis();
+        long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
+
+        if (DEBUG) {
+            Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
+                    newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
+        }
+        return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
+                newLatestRuntimeElapsed, 0 /* backoffAttempt */);
+    }
+
+    // JobCompletedListener implementations.
+
+    /**
+     * A job just finished executing. We fetch the
+     * {@link com.android.server.job.controllers.JobStatus} from the store and depending on
+     * whether we want to reschedule we readd it to the controllers.
+     * @param jobStatus Completed job.
+     * @param needsReschedule Whether the implementing class should reschedule this job.
+     */
+    @Override
+    public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
+        if (DEBUG) {
+            Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
+        }
+        if (!stopTrackingJob(jobStatus)) {
+            if (DEBUG) {
+                Slog.e(TAG, "Error removing job: could not find job to remove. Was job " +
+                        "removed while executing?");
+            }
+            return;
+        }
+        if (needsReschedule) {
+            JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
+            startTrackingJob(rescheduled);
+        } else if (jobStatus.getJob().isPeriodic()) {
+            JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
+            startTrackingJob(rescheduledPeriodic);
+        }
+        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+    }
+
+    // StateChangedListener implementations.
+
+    /**
+     * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
+     * made on the main thread.
+     * For now this takes the job and if it's ready to run it will run it. In future we might not
+     * provide the job, so that the StateChangedListener has to run through its list of jobs to
+     * see which are ready. This will further decouple the controllers from the execution logic.
+     */
+    @Override
+    public void onControllerStateChanged() {
+        // Post a message to to run through the list of jobs and start/stop any that are eligible.
+        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+    }
+
+    @Override
+    public void onRunJobNow(JobStatus jobStatus) {
+        mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
+    }
+
+    /**
+     * Disk I/O is finished, take the list of jobs we read from disk and add them to our
+     * {@link JobStore}.
+     * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
+     * and is called once at boot.
+     */
+    @Override
+    public void onJobMapReadFinished(List<JobStatus> jobs) {
+        synchronized (mJobs) {
+            for (JobStatus js : jobs) {
+                if (mJobs.containsJobIdForUid(js.getJobId(), js.getUid())) {
+                    // An app with BOOT_COMPLETED *might* have decided to reschedule their job, in
+                    // the same amount of time it took us to read it from disk. If this is the case
+                    // we leave it be.
+                    continue;
+                }
+                startTrackingJob(js);
+            }
+        }
+    }
+
+    private class JobHandler extends Handler {
+
+        public JobHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_JOB_EXPIRED:
+                    synchronized (mJobs) {
+                        JobStatus runNow = (JobStatus) message.obj;
+                        if (!mPendingJobs.contains(runNow)) {
+                            mPendingJobs.add(runNow);
+                        }
+                    }
+                    queueReadyJobsForExecutionH();
+                    break;
+                case MSG_CHECK_JOB:
+                    // Check the list of jobs and run some of them if we feel inclined.
+                    maybeQueueReadyJobsForExecutionH();
+                    break;
+            }
+            maybeRunPendingJobsH();
+            // Don't remove JOB_EXPIRED in case one came along while processing the queue.
+            removeMessages(MSG_CHECK_JOB);
+        }
+
+        /**
+         * Run through list of jobs and execute all possible - at least one is expired so we do
+         * as many as we can.
+         */
+        private void queueReadyJobsForExecutionH() {
+            synchronized (mJobs) {
+                for (JobStatus job : mJobs.getJobs()) {
+                    if (isReadyToBeExecutedLocked(job)) {
+                        mPendingJobs.add(job);
+                    } else if (isReadyToBeCancelledLocked(job)) {
+                        stopJobOnServiceContextLocked(job);
+                    }
+                }
+            }
+        }
+
+        /**
+         * The state of at least one job has changed. Here is where we could enforce various
+         * policies on when we want to execute jobs.
+         * Right now the policy is such:
+         * If >1 of the ready jobs is idle mode we send all of them off
+         * if more than 2 network connectivity jobs are ready we send them all off.
+         * If more than 4 jobs total are ready we send them all off.
+         * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
+         */
+        private void maybeQueueReadyJobsForExecutionH() {
+            synchronized (mJobs) {
+                int idleCount = 0;
+                int backoffCount = 0;
+                int connectivityCount = 0;
+                List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
+                for (JobStatus job : mJobs.getJobs()) {
+                    if (isReadyToBeExecutedLocked(job)) {
+                        if (job.getNumFailures() > 0) {
+                            backoffCount++;
+                        }
+                        if (job.hasIdleConstraint()) {
+                            idleCount++;
+                        }
+                        if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
+                            connectivityCount++;
+                        }
+                        runnableJobs.add(job);
+                    } else if (isReadyToBeCancelledLocked(job)) {
+                        stopJobOnServiceContextLocked(job);
+                    }
+                }
+                if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
+                        connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+                        runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
+                    for (JobStatus job : runnableJobs) {
+                        mPendingJobs.add(job);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Criteria for moving a job into the pending queue:
+         *      - It's ready.
+         *      - It's not pending.
+         *      - It's not already running on a JSC.
+         */
+        private boolean isReadyToBeExecutedLocked(JobStatus job) {
+              return job.isReady() && !mPendingJobs.contains(job) && !isCurrentlyActiveLocked(job);
+        }
+
+        /**
+         * Criteria for cancelling an active job:
+         *      - It's not ready
+         *      - It's running on a JSC.
+         */
+        private boolean isReadyToBeCancelledLocked(JobStatus job) {
+            return !job.isReady() && isCurrentlyActiveLocked(job);
+        }
+
+        /**
+         * Reconcile jobs in the pending queue against available execution contexts.
+         * A controller can force a job into the pending queue even if it's already running, but
+         * here is where we decide whether to actually execute it.
+         */
+        private void maybeRunPendingJobsH() {
+            synchronized (mJobs) {
+                Iterator<JobStatus> it = mPendingJobs.iterator();
+                while (it.hasNext()) {
+                    JobStatus nextPending = it.next();
+                    JobServiceContext availableContext = null;
+                    for (JobServiceContext jsc : mActiveServices) {
+                        final JobStatus running = jsc.getRunningJob();
+                        if (running != null && running.matches(nextPending.getUid(),
+                                nextPending.getJobId())) {
+                            // Already running this tId for this uId, skip.
+                            availableContext = null;
+                            break;
+                        }
+                        if (jsc.isAvailable()) {
+                            availableContext = jsc;
+                        }
+                    }
+                    if (availableContext != null) {
+                        if (!availableContext.executeRunnableJob(nextPending)) {
+                            if (DEBUG) {
+                                Slog.d(TAG, "Error executing " + nextPending);
+                            }
+                            mJobs.remove(nextPending);
+                        }
+                        it.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Binder stub trampoline implementation
+     */
+    final class JobSchedulerStub extends IJobScheduler.Stub {
+        /** Cache determination of whether a given app can persist jobs
+         * key is uid of the calling app; value is undetermined/true/false
+         */
+        private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
+
+        // Enforce that only the app itself (or shared uid participant) can schedule a
+        // job that runs one of the app's services, as well as verifying that the
+        // named service properly requires the BIND_JOB_SERVICE permission
+        private void enforceValidJobRequest(int uid, JobInfo job) {
+            final PackageManager pm = getContext().getPackageManager();
+            final ComponentName service = job.getService();
+            try {
+                ServiceInfo si = pm.getServiceInfo(service, 0);
+                if (si.applicationInfo.uid != uid) {
+                    throw new IllegalArgumentException("uid " + uid +
+                            " cannot schedule job in " + service.getPackageName());
+                }
+                if (!JobService.PERMISSION_BIND.equals(si.permission)) {
+                    throw new IllegalArgumentException("Scheduled service " + service
+                            + " does not require android.permission.BIND_JOB_SERVICE permission");
+                }
+            } catch (NameNotFoundException e) {
+                throw new IllegalArgumentException("No such service: " + service);
+            }
+        }
+
+        private boolean canPersistJobs(int pid, int uid) {
+            // If we get this far we're good to go; all we need to do now is check
+            // whether the app is allowed to persist its scheduled work.
+            final boolean canPersist;
+            synchronized (mPersistCache) {
+                Boolean cached = mPersistCache.get(uid);
+                if (cached != null) {
+                    canPersist = cached.booleanValue();
+                } else {
+                    // Persisting jobs is tantamount to running at boot, so we permit
+                    // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
+                    // permission
+                    int result = getContext().checkPermission(
+                            android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
+                    canPersist = (result == PackageManager.PERMISSION_GRANTED);
+                    mPersistCache.put(uid, canPersist);
+                }
+            }
+            return canPersist;
+        }
+
+        // IJobScheduler implementation
+        @Override
+        public int schedule(JobInfo job) throws RemoteException {
+            if (DEBUG) {
+                Slog.d(TAG, "Scheduling job: " + job);
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+
+            enforceValidJobRequest(uid, job);
+            final boolean canPersist = canPersistJobs(pid, uid);
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return JobSchedulerService.this.schedule(job, uid, canPersist);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public List<JobInfo> getAllPendingJobs() throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return JobSchedulerService.this.getPendingJobs(uid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void cancelAll() throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                JobSchedulerService.this.cancelJobsForUid(uid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void cancel(int jobId) throws RemoteException {
+            final int uid = Binder.getCallingUid();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                JobSchedulerService.this.cancelJob(uid, jobId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * "dumpsys" infrastructure
+         */
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+            long identityToken = Binder.clearCallingIdentity();
+            try {
+                JobSchedulerService.this.dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
+    };
+
+    void dumpInternal(PrintWriter pw) {
+        synchronized (mJobs) {
+            pw.println("Registered jobs:");
+            if (mJobs.size() > 0) {
+                for (JobStatus job : mJobs.getJobs()) {
+                    job.dump(pw, "  ");
+                }
+            } else {
+                pw.println();
+                pw.println("No jobs scheduled.");
+            }
+            for (StateController controller : mControllers) {
+                pw.println();
+                controller.dumpControllerState(pw);
+            }
+            pw.println();
+            pw.println("Pending");
+            for (JobStatus jobStatus : mPendingJobs) {
+                pw.println(jobStatus.hashCode());
+            }
+            pw.println();
+            pw.println("Active jobs:");
+            for (JobServiceContext jsc : mActiveServices) {
+                if (jsc.isAvailable()) {
+                    continue;
+                } else {
+                    pw.println(jsc.getRunningJob().hashCode() + " for: " +
+                            (SystemClock.elapsedRealtime()
+                                    - jsc.getExecutionStartTimeElapsed())/1000 + "s " +
+                            "timeout: " + jsc.getTimeoutElapsed());
+                }
+            }
+        }
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
similarity index 66%
rename from services/core/java/com/android/server/task/TaskServiceContext.java
rename to services/core/java/com/android/server/job/JobServiceContext.java
index a21de88..534faba3 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -14,12 +14,12 @@
  * limitations under the License
  */
 
-package com.android.server.task;
+package com.android.server.job;
 
 import android.app.ActivityManager;
-import android.app.task.ITaskCallback;
-import android.app.task.ITaskService;
-import android.app.task.TaskParams;
+import android.app.job.JobParameters;
+import android.app.job.IJobCallback;
+import android.app.job.IJobService;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -39,32 +39,32 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * Handles client binding and lifecycle of a task. A task will only execute one at a time on an
+ * Handles client binding and lifecycle of a job. A job will only execute one at a time on an
  * instance of this class.
  */
-public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
     private static final boolean DEBUG = true;
-    private static final String TAG = "TaskServiceContext";
-    /** Define the maximum # of tasks allowed to run on a service at once. */
-    private static final int defaultMaxActiveTasksPerService =
+    private static final String TAG = "JobServiceContext";
+    /** Define the maximum # of jobs allowed to run on a service at once. */
+    private static final int defaultMaxActiveJobsPerService =
             ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
-    /** Amount of time a task is allowed to execute for before being considered timed-out. */
+    /** Amount of time a job is allowed to execute for before being considered timed-out. */
     private static final long EXECUTING_TIMESLICE_MILLIS = 60 * 1000;
-    /** Amount of time the TaskManager will wait for a response from an app for a message. */
+    /** Amount of time the JobScheduler will wait for a response from an app for a message. */
     private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
     /** String prefix for all wakelock names. */
-    private static final String TM_WAKELOCK_PREFIX = "*task*/";
+    private static final String JS_WAKELOCK_PREFIX = "*job*/";
 
     private static final String[] VERB_STRINGS = {
             "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
     };
 
-    // States that a task occupies while interacting with the client.
+    // States that a job occupies while interacting with the client.
     static final int VERB_BINDING = 0;
     static final int VERB_STARTING = 1;
     static final int VERB_EXECUTING = 2;
@@ -75,30 +75,30 @@
     private static final int MSG_TIMEOUT = 0;
     /** Received a callback from client. */
     private static final int MSG_CALLBACK = 1;
-    /** Run through list and start any ready tasks.*/
+    /** Run through list and start any ready jobs.*/
     private static final int MSG_SERVICE_BOUND = 2;
-    /** Cancel a task. */
+    /** Cancel a job. */
     private static final int MSG_CANCEL = 3;
-    /** Shutdown the Task. Used when the client crashes and we can't die gracefully.*/
+    /** Shutdown the job. Used when the client crashes and we can't die gracefully.*/
     private static final int MSG_SHUTDOWN_EXECUTION = 4;
 
     private final Handler mCallbackHandler;
-    /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
-    private final TaskCompletedListener mCompletedListener;
+    /** Make callbacks to {@link JobSchedulerService} to inform on job completion status. */
+    private final JobCompletedListener mCompletedListener;
     /** Used for service binding, etc. */
     private final Context mContext;
     private PowerManager.WakeLock mWakeLock;
 
     // Execution state.
-    private TaskParams mParams;
+    private JobParameters mParams;
     @VisibleForTesting
     int mVerb;
     private AtomicBoolean mCancelled = new AtomicBoolean();
 
-    /** All the information maintained about the task currently being executed. */
-    private TaskStatus mRunningTask;
+    /** All the information maintained about the job currently being executed. */
+    private JobStatus mRunningJob;
     /** Binder to the client service. */
-    ITaskService service;
+    IJobService service;
 
     private final Object mLock = new Object();
     /** Whether this context is free. */
@@ -109,45 +109,45 @@
     /** Track when job will timeout. */
     private long mTimeoutElapsed;
 
-    TaskServiceContext(TaskManagerService service, Looper looper) {
+    JobServiceContext(JobSchedulerService service, Looper looper) {
         this(service.getContext(), service, looper);
     }
 
     @VisibleForTesting
-    TaskServiceContext(Context context, TaskCompletedListener completedListener, Looper looper) {
+    JobServiceContext(Context context, JobCompletedListener completedListener, Looper looper) {
         mContext = context;
-        mCallbackHandler = new TaskServiceHandler(looper);
+        mCallbackHandler = new JobServiceHandler(looper);
         mCompletedListener = completedListener;
         mAvailable = true;
     }
 
     /**
-     * Give a task to this context for execution. Callers must first check {@link #isAvailable()}
+     * Give a job to this context for execution. Callers must first check {@link #isAvailable()}
      * to make sure this is a valid context.
-     * @param ts The status of the task that we are going to run.
-     * @return True if the task is valid and is running. False if the task cannot be executed.
+     * @param job The status of the job that we are going to run.
+     * @return True if the job is valid and is running. False if the job cannot be executed.
      */
-    boolean executeRunnableTask(TaskStatus ts) {
+    boolean executeRunnableJob(JobStatus job) {
         synchronized (mLock) {
             if (!mAvailable) {
                 Slog.e(TAG, "Starting new runnable but context is unavailable > Error.");
                 return false;
             }
 
-            mRunningTask = ts;
-            mParams = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
+            mRunningJob = job;
+            mParams = new JobParameters(job.getJobId(), job.getExtras(), this);
             mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
 
             mVerb = VERB_BINDING;
-            final Intent intent = new Intent().setComponent(ts.getServiceComponent());
+            final Intent intent = new Intent().setComponent(job.getServiceComponent());
             boolean binding = mContext.bindServiceAsUser(intent, this,
                     Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
-                    new UserHandle(ts.getUserId()));
+                    new UserHandle(job.getUserId()));
             if (!binding) {
                 if (DEBUG) {
-                    Slog.d(TAG, ts.getServiceComponent().getShortClassName() + " unavailable.");
+                    Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
                 }
-                mRunningTask = null;
+                mRunningJob = null;
                 mParams = null;
                 mExecutionStartTimeElapsed = 0L;
                 return false;
@@ -157,13 +157,13 @@
         }
     }
 
-    /** Used externally to query the running task. Will return null if there is no task running. */
-    TaskStatus getRunningTask() {
-        return mRunningTask;
+    /** Used externally to query the running job. Will return null if there is no job running. */
+    JobStatus getRunningJob() {
+        return mRunningJob;
     }
 
-    /** Called externally when a task that was scheduled for execution should be cancelled. */
-    void cancelExecutingTask() {
+    /** Called externally when a job that was scheduled for execution should be cancelled. */
+    void cancelExecutingJob() {
         mCallbackHandler.obtainMessage(MSG_CANCEL).sendToTarget();
     }
 
@@ -185,29 +185,29 @@
     }
 
     @Override
-    public void taskFinished(int taskId, boolean reschedule) {
+    public void jobFinished(int jobId, boolean reschedule) {
         if (!verifyCallingUid()) {
             return;
         }
-        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
                 .sendToTarget();
     }
 
     @Override
-    public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+    public void acknowledgeStopMessage(int jobId, boolean reschedule) {
         if (!verifyCallingUid()) {
             return;
         }
-        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
                 .sendToTarget();
     }
 
     @Override
-    public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+    public void acknowledgeStartMessage(int jobId, boolean ongoing) {
         if (!verifyCallingUid()) {
             return;
         }
-        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, ongoing ? 1 : 0).sendToTarget();
     }
 
     /**
@@ -219,25 +219,25 @@
      */
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
-        if (!name.equals(mRunningTask.getServiceComponent())) {
+        if (!name.equals(mRunningJob.getServiceComponent())) {
             mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
             return;
         }
-        this.service = ITaskService.Stub.asInterface(service);
+        this.service = IJobService.Stub.asInterface(service);
         // Remove all timeouts.
         mCallbackHandler.removeMessages(MSG_TIMEOUT);
         final PowerManager pm =
                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                TM_WAKELOCK_PREFIX + mRunningTask.getServiceComponent().getPackageName());
-        mWakeLock.setWorkSource(new WorkSource(mRunningTask.getUid()));
+                JS_WAKELOCK_PREFIX + mRunningJob.getServiceComponent().getPackageName());
+        mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
         mWakeLock.setReferenceCounted(false);
         mWakeLock.acquire();
         mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
     }
 
     /**
-     * If the client service crashes we reschedule this task and clean up.
+     * If the client service crashes we reschedule this job and clean up.
      * @param name The concrete component name of the service whose
      */
     @Override
@@ -251,7 +251,7 @@
      * @return True if the binder calling is coming from the client we expect.
      */
     private boolean verifyCallingUid() {
-        if (mRunningTask == null || Binder.getCallingUid() != mRunningTask.getUid()) {
+        if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
             if (DEBUG) {
                 Slog.d(TAG, "Stale callback received, ignoring.");
             }
@@ -261,12 +261,12 @@
     }
 
     /**
-     * Handles the lifecycle of the TaskService binding/callbacks, etc. The convention within this
+     * Handles the lifecycle of the JobService binding/callbacks, etc. The convention within this
      * class is to append 'H' to each function name that can only be called on this handler. This
      * isn't strictly necessary because all of these functions are private, but helps clarity.
      */
-    private class TaskServiceHandler extends Handler {
-        TaskServiceHandler(Looper looper) {
+    private class JobServiceHandler extends Handler {
+        JobServiceHandler(Looper looper) {
             super(looper);
         }
 
@@ -278,7 +278,7 @@
                     break;
                 case MSG_CALLBACK:
                     if (DEBUG) {
-                        Slog.d(TAG, "MSG_CALLBACK of : " + mRunningTask + " v:" +
+                        Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob + " v:" +
                                 VERB_STRINGS[mVerb]);
                     }
                     removeMessages(MSG_TIMEOUT);
@@ -292,7 +292,7 @@
                         handleFinishedH(reschedule);
                     } else {
                         if (DEBUG) {
-                            Slog.d(TAG, "Unrecognised callback: " + mRunningTask);
+                            Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
                         }
                     }
                     break;
@@ -303,42 +303,42 @@
                     handleOpTimeoutH();
                     break;
                 case MSG_SHUTDOWN_EXECUTION:
-                    closeAndCleanupTaskH(true /* needsReschedule */);
+                    closeAndCleanupJobH(true /* needsReschedule */);
                     break;
                 default:
                     Log.e(TAG, "Unrecognised message: " + message);
             }
         }
 
-        /** Start the task on the service. */
+        /** Start the job on the service. */
         private void handleServiceBoundH() {
             if (mVerb != VERB_BINDING) {
-                Slog.e(TAG, "Sending onStartTask for a task that isn't pending. "
+                Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
                         + VERB_STRINGS[mVerb]);
-                closeAndCleanupTaskH(false /* reschedule */);
+                closeAndCleanupJobH(false /* reschedule */);
                 return;
             }
             if (mCancelled.get()) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Task cancelled while waiting for bind to complete. "
-                            + mRunningTask);
+                    Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
+                            + mRunningJob);
                 }
-                closeAndCleanupTaskH(true /* reschedule */);
+                closeAndCleanupJobH(true /* reschedule */);
                 return;
             }
             try {
                 mVerb = VERB_STARTING;
                 scheduleOpTimeOut();
-                service.startTask(mParams);
+                service.startJob(mParams);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error sending onStart message to '" +
-                        mRunningTask.getServiceComponent().getShortClassName() + "' ", e);
+                        mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
             }
         }
 
         /**
          * State behaviours.
-         * VERB_STARTING   -> Successful start, change task to VERB_EXECUTING and post timeout.
+         * VERB_STARTING   -> Successful start, change job to VERB_EXECUTING and post timeout.
          *     _PENDING    -> Error
          *     _EXECUTING  -> Error
          *     _STOPPING   -> Error
@@ -348,7 +348,7 @@
                 case VERB_STARTING:
                     mVerb = VERB_EXECUTING;
                     if (!workOngoing) {
-                        // Task is finished already so fast-forward to handleFinished.
+                        // Job is finished already so fast-forward to handleFinished.
                         handleFinishedH(false);
                         return;
                     }
@@ -360,14 +360,14 @@
                     scheduleOpTimeOut();
                     break;
                 default:
-                    Log.e(TAG, "Handling started task but task wasn't starting! Was "
+                    Log.e(TAG, "Handling started job but job wasn't starting! Was "
                             + VERB_STRINGS[mVerb] + ".");
                     return;
             }
         }
 
         /**
-         * VERB_EXECUTING  -> Client called taskFinished(), clean up and notify done.
+         * VERB_EXECUTING  -> Client called jobFinished(), clean up and notify done.
          *     _STOPPING   -> Successful finish, clean up and notify done.
          *     _STARTING   -> Error
          *     _PENDING    -> Error
@@ -376,20 +376,20 @@
             switch (mVerb) {
                 case VERB_EXECUTING:
                 case VERB_STOPPING:
-                    closeAndCleanupTaskH(reschedule);
+                    closeAndCleanupJobH(reschedule);
                     break;
                 default:
-                    Slog.e(TAG, "Got an execution complete message for a task that wasn't being" +
+                    Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
                             "executed. Was " + VERB_STRINGS[mVerb] + ".");
             }
         }
 
         /**
-         * A task can be in various states when a cancel request comes in:
+         * A job can be in various states when a cancel request comes in:
          * VERB_BINDING    -> Cancelled before bind completed. Mark as cancelled and wait for
          *                    {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
          *     _STARTING   -> Mark as cancelled and wait for
-         *                    {@link TaskServiceContext#acknowledgeStartMessage(int, boolean)}
+         *                    {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
          *     _EXECUTING  -> call {@link #sendStopMessageH}}.
          *     _ENDING     -> No point in doing anything here, so we ignore.
          */
@@ -406,48 +406,48 @@
                     // Nada.
                     break;
                 default:
-                    Slog.e(TAG, "Cancelling a task without a valid verb: " + mVerb);
+                    Slog.e(TAG, "Cancelling a job without a valid verb: " + mVerb);
                     break;
             }
         }
 
         /** Process MSG_TIMEOUT here. */
         private void handleOpTimeoutH() {
-            if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+            if (Log.isLoggable(JobSchedulerService.TAG, Log.DEBUG)) {
                 Log.d(TAG, "MSG_TIMEOUT of " +
-                        mRunningTask.getServiceComponent().getShortClassName() + " : "
-                        + mParams.getTaskId());
+                        mRunningJob.getServiceComponent().getShortClassName() + " : "
+                        + mParams.getJobId());
             }
 
-            final int taskId = mParams.getTaskId();
+            final int jobId = mParams.getJobId();
             switch (mVerb) {
                 case VERB_STARTING:
                     // Client unresponsive - wedged or failed to respond in time. We don't really
-                    // know what happened so let's log it and notify the TaskManager
+                    // know what happened so let's log it and notify the JobScheduler
                     // FINISHED/NO-RETRY.
-                    Log.e(TAG, "No response from client for onStartTask '" +
-                            mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
-                            + taskId);
-                    closeAndCleanupTaskH(false /* needsReschedule */);
+                    Log.e(TAG, "No response from client for onStartJob '" +
+                            mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+                            + jobId);
+                    closeAndCleanupJobH(false /* needsReschedule */);
                     break;
                 case VERB_STOPPING:
-                    // At least we got somewhere, so fail but ask the TaskManager to reschedule.
-                    Log.e(TAG, "No response from client for onStopTask, '" +
-                            mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
-                            + taskId);
-                    closeAndCleanupTaskH(true /* needsReschedule */);
+                    // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
+                    Log.e(TAG, "No response from client for onStopJob, '" +
+                            mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+                            + jobId);
+                    closeAndCleanupJobH(true /* needsReschedule */);
                     break;
                 case VERB_EXECUTING:
                     // Not an error - client ran out of time.
-                    Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
+                    Log.i(TAG, "Client timed out while executing (no jobFinished received)." +
                             " sending onStop. "  +
-                            mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
-                            + taskId);
+                            mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+                            + jobId);
                     sendStopMessageH();
                     break;
                 default:
-                    Log.e(TAG, "Handling timeout for an unknown active task state: "
-                            + mRunningTask);
+                    Log.e(TAG, "Handling timeout for an unknown active job state: "
+                            + mRunningJob);
                     return;
             }
         }
@@ -459,35 +459,34 @@
         private void sendStopMessageH() {
             mCallbackHandler.removeMessages(MSG_TIMEOUT);
             if (mVerb != VERB_EXECUTING) {
-                Log.e(TAG, "Sending onStopTask for a task that isn't started. " + mRunningTask);
-                closeAndCleanupTaskH(false /* reschedule */);
+                Log.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
+                closeAndCleanupJobH(false /* reschedule */);
                 return;
             }
             try {
                 mVerb = VERB_STOPPING;
                 scheduleOpTimeOut();
-                service.stopTask(mParams);
+                service.stopJob(mParams);
             } catch (RemoteException e) {
-                Log.e(TAG, "Error sending onStopTask to client.", e);
-                closeAndCleanupTaskH(false /* reschedule */);
+                Log.e(TAG, "Error sending onStopJob to client.", e);
+                closeAndCleanupJobH(false /* reschedule */);
             }
         }
 
         /**
-         * The provided task has finished, either by calling
-         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+         * The provided job has finished, either by calling
+         * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
          * or from acknowledging the stop message we sent. Either way, we're done tracking it and
          * we want to clean up internally.
          */
-        private void closeAndCleanupTaskH(boolean reschedule) {
+        private void closeAndCleanupJobH(boolean reschedule) {
             removeMessages(MSG_TIMEOUT);
+            mCompletedListener.onJobCompleted(mRunningJob, reschedule);
             synchronized (mLock) {
                 mWakeLock.release();
-                mContext.unbindService(TaskServiceContext.this);
-                mCompletedListener.onTaskCompleted(mRunningTask, reschedule);
-
+                mContext.unbindService(JobServiceContext.this);
                 mWakeLock = null;
-                mRunningTask = null;
+                mRunningJob = null;
                 mParams = null;
                 mVerb = -1;
                 mCancelled.set(false);
@@ -508,8 +507,8 @@
                     EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
             if (DEBUG) {
                 Slog.d(TAG, "Scheduling time out for '" +
-                        mRunningTask.getServiceComponent().getShortClassName() + "' tId: " +
-                        mParams.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+                        mRunningJob.getServiceComponent().getShortClassName() + "' tId: " +
+                        mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
             }
             Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
             mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
new file mode 100644
index 0000000..4ac26c1
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -0,0 +1,669 @@
+/*
+ * 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.job;
+
+import android.content.ComponentName;
+import android.app.job.JobInfo;
+import android.content.Context;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.AtomicFile;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.server.IoThread;
+import com.android.server.job.controllers.JobStatus;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these jobs.
+ * This class offers the following functionality:
+ *     - When a job is added, it will determine if the job requirements have changed (update) and
+ *       whether the controllers need to be updated.
+ *     - Persists JobInfos, figures out when to to rewrite the JobInfo to disk.
+ *     - Handles rescheduling of jobs.
+ *       - When a periodic job is executed and must be re-added.
+ *       - When a job fails and the client requests that it be retried with backoff.
+ *       - This class <strong>is not</strong> thread-safe.
+ *
+ * Note on locking:
+ *      All callers to this class must <strong>lock on the class object they are calling</strong>.
+ *      This is important b/c {@link com.android.server.job.JobStore.WriteJobsMapToDiskRunnable}
+ *      and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
+ *      object.
+ */
+public class JobStore {
+    private static final String TAG = "JobStore";
+    private static final boolean DEBUG = JobSchedulerService.DEBUG;
+
+    /** Threshold to adjust how often we want to write to the db. */
+    private static final int MAX_OPS_BEFORE_WRITE = 1;
+    final ArraySet<JobStatus> mJobSet;
+    final Context mContext;
+
+    private int mDirtyOperations;
+
+    private static final Object sSingletonLock = new Object();
+    private final AtomicFile mJobsFile;
+    /** Handler backed by IoThread for writing to disk. */
+    private final Handler mIoHandler = IoThread.getHandler();
+    private static JobStore sSingleton;
+
+    /** Used by the {@link JobSchedulerService} to instantiate the JobStore. */
+    static JobStore initAndGet(JobSchedulerService jobManagerService) {
+        synchronized (sSingletonLock) {
+            if (sSingleton == null) {
+                sSingleton = new JobStore(jobManagerService.getContext(),
+                        Environment.getDataDirectory(), jobManagerService);
+            }
+            return sSingleton;
+        }
+    }
+
+    @VisibleForTesting
+    public static JobStore initAndGetForTesting(Context context, File dataDir,
+                                                 JobMapReadFinishedListener callback) {
+        return new JobStore(context, dataDir, callback);
+    }
+
+    private JobStore(Context context, File dataDir, JobMapReadFinishedListener callback) {
+        mContext = context;
+        mDirtyOperations = 0;
+
+        File systemDir = new File(dataDir, "system");
+        File jobDir = new File(systemDir, "job");
+        jobDir.mkdirs();
+        mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
+
+        mJobSet = new ArraySet<JobStatus>();
+
+        readJobMapFromDiskAsync(callback);
+    }
+
+    /**
+     * Add a job to the master list, persisting it if necessary. If the JobStatus already exists,
+     * it will be replaced.
+     * @param jobStatus Job to add.
+     * @return Whether or not an equivalent JobStatus was replaced by this operation.
+     */
+    public boolean add(JobStatus jobStatus) {
+        boolean replaced = mJobSet.remove(jobStatus);
+        mJobSet.add(jobStatus);
+        if (jobStatus.isPersisted()) {
+            maybeWriteStatusToDiskAsync();
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "Added job status to store: " + jobStatus);
+        }
+        return replaced;
+    }
+
+    /**
+     * Whether this jobStatus object already exists in the JobStore.
+     */
+    public boolean containsJobIdForUid(int jobId, int uId) {
+        for (JobStatus ts : mJobSet) {
+            if (ts.getUid() == uId && ts.getJobId() == jobId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public int size() {
+        return mJobSet.size();
+    }
+
+    /**
+     * Remove the provided job. Will also delete the job if it was persisted.
+     * @return Whether or not the job existed to be removed.
+     */
+    public boolean remove(JobStatus jobStatus) {
+        boolean removed = mJobSet.remove(jobStatus);
+        if (!removed) {
+            if (DEBUG) {
+                Slog.d(TAG, "Couldn't remove job: didn't exist: " + jobStatus);
+            }
+            return false;
+        }
+        maybeWriteStatusToDiskAsync();
+        return removed;
+    }
+
+    @VisibleForTesting
+    public void clear() {
+        mJobSet.clear();
+        maybeWriteStatusToDiskAsync();
+    }
+
+    public List<JobStatus> getJobsByUser(int userHandle) {
+        List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+        Iterator<JobStatus> it = mJobSet.iterator();
+        while (it.hasNext()) {
+            JobStatus ts = it.next();
+            if (UserHandle.getUserId(ts.getUid()) == userHandle) {
+                matchingJobs.add(ts);
+            }
+        }
+        return matchingJobs;
+    }
+
+    /**
+     * @param uid Uid of the requesting app.
+     * @return All JobStatus objects for a given uid from the master list.
+     */
+    public List<JobStatus> getJobsByUid(int uid) {
+        List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+        Iterator<JobStatus> it = mJobSet.iterator();
+        while (it.hasNext()) {
+            JobStatus ts = it.next();
+            if (ts.getUid() == uid) {
+                matchingJobs.add(ts);
+            }
+        }
+        return matchingJobs;
+    }
+
+    /**
+     * @param uid Uid of the requesting app.
+     * @param jobId Job id, specified at schedule-time.
+     * @return the JobStatus that matches the provided uId and jobId, or null if none found.
+     */
+    public JobStatus getJobByUidAndJobId(int uid, int jobId) {
+        Iterator<JobStatus> it = mJobSet.iterator();
+        while (it.hasNext()) {
+            JobStatus ts = it.next();
+            if (ts.getUid() == uid && ts.getJobId() == jobId) {
+                return ts;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return The live array of JobStatus objects.
+     */
+    public ArraySet<JobStatus> getJobs() {
+        return mJobSet;
+    }
+
+    /** Version of the db schema. */
+    private static final int JOBS_FILE_VERSION = 0;
+    /** Tag corresponds to constraints this job needs. */
+    private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints";
+    /** Tag corresponds to execution parameters. */
+    private static final String XML_TAG_PERIODIC = "periodic";
+    private static final String XML_TAG_ONEOFF = "one-off";
+    private static final String XML_TAG_EXTRAS = "extras";
+
+    /**
+     * Every time the state changes we write all the jobs in one swath, instead of trying to
+     * track incremental changes.
+     * @return Whether the operation was successful. This will only fail for e.g. if the system is
+     * low on storage. If this happens, we continue as normal
+     */
+    private void maybeWriteStatusToDiskAsync() {
+        mDirtyOperations++;
+        if (mDirtyOperations >= MAX_OPS_BEFORE_WRITE) {
+            if (DEBUG) {
+                Slog.v(TAG, "Writing jobs to disk.");
+            }
+            mIoHandler.post(new WriteJobsMapToDiskRunnable());
+        }
+    }
+
+    private void readJobMapFromDiskAsync(JobMapReadFinishedListener callback) {
+        mIoHandler.post(new ReadJobMapFromDiskRunnable(callback));
+    }
+
+    public void readJobMapFromDisk(JobMapReadFinishedListener callback) {
+        new ReadJobMapFromDiskRunnable(callback).run();
+    }
+
+    /**
+     * Runnable that writes {@link #mJobSet} out to xml.
+     * NOTE: This Runnable locks on JobStore.this
+     */
+    private class WriteJobsMapToDiskRunnable implements Runnable {
+        @Override
+        public void run() {
+            final long startElapsed = SystemClock.elapsedRealtime();
+            List<JobStatus> mStoreCopy = new ArrayList<JobStatus>();
+            synchronized (JobStore.this) {
+                // Copy over the jobs so we can release the lock before writing.
+                for (JobStatus jobStatus : mJobSet) {
+                    JobStatus copy = new JobStatus(jobStatus.getJob(), jobStatus.getUid(),
+                            jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
+                    mStoreCopy.add(copy);
+                }
+            }
+            writeJobsMapImpl(mStoreCopy);
+            if (JobSchedulerService.DEBUG) {
+                Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
+                        - startElapsed) + "ms");
+            }
+        }
+
+        private void writeJobsMapImpl(List<JobStatus> jobList) {
+            try {
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(baos, "utf-8");
+                out.startDocument(null, true);
+                out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+                out.startTag(null, "job-info");
+                out.attribute(null, "version", Integer.toString(JOBS_FILE_VERSION));
+                for (JobStatus jobStatus : jobList) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Saving job " + jobStatus.getJobId());
+                    }
+                    out.startTag(null, "job");
+                    addIdentifierAttributesToJobTag(out, jobStatus);
+                    writeConstraintsToXml(out, jobStatus);
+                    writeExecutionCriteriaToXml(out, jobStatus);
+                    writeBundleToXml(jobStatus.getExtras(), out);
+                    out.endTag(null, "job");
+                }
+                out.endTag(null, "job-info");
+                out.endDocument();
+
+                // Write out to disk in one fell sweep.
+                FileOutputStream fos = mJobsFile.startWrite();
+                fos.write(baos.toByteArray());
+                mJobsFile.finishWrite(fos);
+                mDirtyOperations = 0;
+            } catch (IOException e) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Error writing out job data.", e);
+                }
+            } catch (XmlPullParserException e) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Error persisting bundle.", e);
+                }
+            }
+        }
+
+        /** Write out a tag with data comprising the required fields of this job and its client. */
+        private void addIdentifierAttributesToJobTag(XmlSerializer out, JobStatus jobStatus)
+                throws IOException {
+            out.attribute(null, "jobid", Integer.toString(jobStatus.getJobId()));
+            out.attribute(null, "package", jobStatus.getServiceComponent().getPackageName());
+            out.attribute(null, "class", jobStatus.getServiceComponent().getClassName());
+            out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
+        }
+
+        private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
+                throws IOException, XmlPullParserException {
+            out.startTag(null, XML_TAG_EXTRAS);
+            extras.saveToXml(out);
+            out.endTag(null, XML_TAG_EXTRAS);
+        }
+        /**
+         * Write out a tag with data identifying this job's constraints. If the constraint isn't here
+         * it doesn't apply.
+         */
+        private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
+            out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
+            if (jobStatus.hasUnmeteredConstraint()) {
+                out.attribute(null, "unmetered", Boolean.toString(true));
+            }
+            if (jobStatus.hasConnectivityConstraint()) {
+                out.attribute(null, "connectivity", Boolean.toString(true));
+            }
+            if (jobStatus.hasIdleConstraint()) {
+                out.attribute(null, "idle", Boolean.toString(true));
+            }
+            if (jobStatus.hasChargingConstraint()) {
+                out.attribute(null, "charging", Boolean.toString(true));
+            }
+            out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
+        }
+
+        private void writeExecutionCriteriaToXml(XmlSerializer out, JobStatus jobStatus)
+                throws IOException {
+            final JobInfo job = jobStatus.getJob();
+            if (jobStatus.getJob().isPeriodic()) {
+                out.startTag(null, XML_TAG_PERIODIC);
+                out.attribute(null, "period", Long.toString(job.getIntervalMillis()));
+            } else {
+                out.startTag(null, XML_TAG_ONEOFF);
+            }
+
+            if (jobStatus.hasDeadlineConstraint()) {
+                // Wall clock deadline.
+                final long deadlineWallclock =  System.currentTimeMillis() +
+                        (jobStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime());
+                out.attribute(null, "deadline", Long.toString(deadlineWallclock));
+            }
+            if (jobStatus.hasTimingDelayConstraint()) {
+                final long delayWallclock = System.currentTimeMillis() +
+                        (jobStatus.getEarliestRunTime() - SystemClock.elapsedRealtime());
+                out.attribute(null, "delay", Long.toString(delayWallclock));
+            }
+
+            // Only write out back-off policy if it differs from the default.
+            // This also helps the case where the job is idle -> these aren't allowed to specify
+            // back-off.
+            if (jobStatus.getJob().getInitialBackoffMillis() != JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS
+                    || jobStatus.getJob().getBackoffPolicy() != JobInfo.DEFAULT_BACKOFF_POLICY) {
+                out.attribute(null, "backoff-policy", Integer.toString(job.getBackoffPolicy()));
+                out.attribute(null, "initial-backoff", Long.toString(job.getInitialBackoffMillis()));
+            }
+            if (job.isPeriodic()) {
+                out.endTag(null, XML_TAG_PERIODIC);
+            } else {
+                out.endTag(null, XML_TAG_ONEOFF);
+            }
+        }
+    }
+
+    /**
+     * Runnable that reads list of persisted job from xml.
+     * NOTE: This Runnable locks on JobStore.this
+     */
+    private class ReadJobMapFromDiskRunnable implements Runnable {
+        private JobMapReadFinishedListener mCallback;
+        public ReadJobMapFromDiskRunnable(JobMapReadFinishedListener callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void run() {
+            try {
+                List<JobStatus> jobs;
+                FileInputStream fis = mJobsFile.openRead();
+                synchronized (JobStore.this) {
+                    jobs = readJobMapImpl(fis);
+                }
+                fis.close();
+                if (jobs != null) {
+                    mCallback.onJobMapReadFinished(jobs);
+                }
+            } catch (FileNotFoundException e) {
+                if (JobSchedulerService.DEBUG) {
+                    Slog.d(TAG, "Could not find jobs file, probably there was nothing to load.");
+                }
+            } catch (XmlPullParserException e) {
+                if (JobSchedulerService.DEBUG) {
+                    Slog.d(TAG, "Error parsing xml.", e);
+                }
+            } catch (IOException e) {
+                if (JobSchedulerService.DEBUG) {
+                    Slog.d(TAG, "Error parsing xml.", e);
+                }
+            }
+        }
+
+        private List<JobStatus> readJobMapImpl(FileInputStream fis) throws XmlPullParserException, IOException {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(fis, null);
+
+            int eventType = parser.getEventType();
+            while (eventType != XmlPullParser.START_TAG &&
+                    eventType != XmlPullParser.END_DOCUMENT) {
+                eventType = parser.next();
+                Slog.d(TAG, parser.getName());
+            }
+            if (eventType == XmlPullParser.END_DOCUMENT) {
+                if (DEBUG) {
+                    Slog.d(TAG, "No persisted jobs.");
+                }
+                return null;
+            }
+
+            String tagName = parser.getName();
+            if ("job-info".equals(tagName)) {
+                final List<JobStatus> jobs = new ArrayList<JobStatus>();
+                // Read in version info.
+                try {
+                    int version = Integer.valueOf(parser.getAttributeValue(null, "version"));
+                    if (version != JOBS_FILE_VERSION) {
+                        Slog.d(TAG, "Invalid version number, aborting jobs file read.");
+                        return null;
+                    }
+                } catch (NumberFormatException e) {
+                    Slog.e(TAG, "Invalid version number, aborting jobs file read.");
+                    return null;
+                }
+                eventType = parser.next();
+                do {
+                    // Read each <job/>
+                    if (eventType == XmlPullParser.START_TAG) {
+                        tagName = parser.getName();
+                        // Start reading job.
+                        if ("job".equals(tagName)) {
+                            JobStatus persistedJob = restoreJobFromXml(parser);
+                            if (persistedJob != null) {
+                                if (DEBUG) {
+                                    Slog.d(TAG, "Read out " + persistedJob);
+                                }
+                                jobs.add(persistedJob);
+                            } else {
+                                Slog.d(TAG, "Error reading job from file.");
+                            }
+                        }
+                    }
+                    eventType = parser.next();
+                } while (eventType != XmlPullParser.END_DOCUMENT);
+                return jobs;
+            }
+            return null;
+        }
+
+        /**
+         * @param parser Xml parser at the beginning of a "<job/>" tag. The next "parser.next()" call
+         *               will take the parser into the body of the job tag.
+         * @return Newly instantiated job holding all the information we just read out of the xml tag.
+         */
+        private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
+                IOException {
+            JobInfo.Builder jobBuilder;
+            int uid;
+
+            // Read out job identifier attributes.
+            try {
+                jobBuilder = buildBuilderFromXml(parser);
+                uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
+            } catch (NumberFormatException e) {
+                Slog.e(TAG, "Error parsing job's required fields, skipping");
+                return null;
+            }
+
+            int eventType;
+            // Read out constraints tag.
+            do {
+                eventType = parser.next();
+            } while (eventType == XmlPullParser.TEXT);  // Push through to next START_TAG.
+
+            if (!(eventType == XmlPullParser.START_TAG &&
+                    XML_TAG_PARAMS_CONSTRAINTS.equals(parser.getName()))) {
+                // Expecting a <constraints> start tag.
+                return null;
+            }
+            try {
+                buildConstraintsFromXml(jobBuilder, parser);
+            } catch (NumberFormatException e) {
+                Slog.d(TAG, "Error reading constraints, skipping.");
+                return null;
+            }
+            parser.next(); // Consume </constraints>
+
+            // Read out execution parameters tag.
+            do {
+                eventType = parser.next();
+            } while (eventType == XmlPullParser.TEXT);
+            if (eventType != XmlPullParser.START_TAG) {
+                return null;
+            }
+
+            Pair<Long, Long> runtimes;
+            try {
+                runtimes = buildExecutionTimesFromXml(parser);
+            } catch (NumberFormatException e) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Error parsing execution time parameters, skipping.");
+                }
+                return null;
+            }
+
+            if (XML_TAG_PERIODIC.equals(parser.getName())) {
+                try {
+                    String val = parser.getAttributeValue(null, "period");
+                    jobBuilder.setPeriodic(Long.valueOf(val));
+                } catch (NumberFormatException e) {
+                    Slog.d(TAG, "Error reading periodic execution criteria, skipping.");
+                    return null;
+                }
+            } else if (XML_TAG_ONEOFF.equals(parser.getName())) {
+                try {
+                    if (runtimes.first != JobStatus.NO_EARLIEST_RUNTIME) {
+                        jobBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
+                    }
+                    if (runtimes.second != JobStatus.NO_LATEST_RUNTIME) {
+                        jobBuilder.setOverrideDeadline(
+                                runtimes.second - SystemClock.elapsedRealtime());
+                    }
+                } catch (NumberFormatException e) {
+                    Slog.d(TAG, "Error reading job execution criteria, skipping.");
+                    return null;
+                }
+            } else {
+                if (DEBUG) {
+                    Slog.d(TAG, "Invalid parameter tag, skipping - " + parser.getName());
+                }
+                // Expecting a parameters start tag.
+                return null;
+            }
+            maybeBuildBackoffPolicyFromXml(jobBuilder, parser);
+
+            parser.nextTag(); // Consume parameters end tag.
+
+            // Read out extras Bundle.
+            do {
+                eventType = parser.next();
+            } while (eventType == XmlPullParser.TEXT);
+            if (!(eventType == XmlPullParser.START_TAG && XML_TAG_EXTRAS.equals(parser.getName()))) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Error reading extras, skipping.");
+                }
+                return null;
+            }
+
+            PersistableBundle extras = PersistableBundle.restoreFromXml(parser);
+            jobBuilder.setExtras(extras);
+            parser.nextTag(); // Consume </extras>
+
+            return new JobStatus(jobBuilder.build(), uid, runtimes.first, runtimes.second);
+        }
+
+        private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
+            // Pull out required fields from <job> attributes.
+            int jobId = Integer.valueOf(parser.getAttributeValue(null, "jobid"));
+            String packageName = parser.getAttributeValue(null, "package");
+            String className = parser.getAttributeValue(null, "class");
+            ComponentName cname = new ComponentName(packageName, className);
+
+            return new JobInfo.Builder(jobId, cname);
+        }
+
+        private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
+            String val = parser.getAttributeValue(null, "unmetered");
+            if (val != null) {
+                jobBuilder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
+            }
+            val = parser.getAttributeValue(null, "connectivity");
+            if (val != null) {
+                jobBuilder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
+            }
+            val = parser.getAttributeValue(null, "idle");
+            if (val != null) {
+                jobBuilder.setRequiresDeviceIdle(true);
+            }
+            val = parser.getAttributeValue(null, "charging");
+            if (val != null) {
+                jobBuilder.setRequiresCharging(true);
+            }
+        }
+
+        /**
+         * Builds the back-off policy out of the params tag. These attributes may not exist, depending
+         * on whether the back-off was set when the job was first scheduled.
+         */
+        private void maybeBuildBackoffPolicyFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
+            String val = parser.getAttributeValue(null, "initial-backoff");
+            if (val != null) {
+                long initialBackoff = Long.valueOf(val);
+                val = parser.getAttributeValue(null, "backoff-policy");
+                int backoffPolicy = Integer.valueOf(val);  // Will throw NFE which we catch higher up.
+                jobBuilder.setBackoffCriteria(initialBackoff, backoffPolicy);
+            }
+        }
+
+        /**
+         * Convenience function to read out and convert deadline and delay from xml into elapsed real
+         * time.
+         * @return A {@link android.util.Pair}, where the first value is the earliest elapsed runtime
+         * and the second is the latest elapsed runtime.
+         */
+        private Pair<Long, Long> buildExecutionTimesFromXml(XmlPullParser parser)
+                throws NumberFormatException {
+            // Pull out execution time data.
+            final long nowWallclock = System.currentTimeMillis();
+            final long nowElapsed = SystemClock.elapsedRealtime();
+
+            long earliestRunTimeElapsed = JobStatus.NO_EARLIEST_RUNTIME;
+            long latestRunTimeElapsed = JobStatus.NO_LATEST_RUNTIME;
+            String val = parser.getAttributeValue(null, "deadline");
+            if (val != null) {
+                long latestRuntimeWallclock = Long.valueOf(val);
+                long maxDelayElapsed =
+                        Math.max(latestRuntimeWallclock - nowWallclock, 0);
+                latestRunTimeElapsed = nowElapsed + maxDelayElapsed;
+            }
+            val = parser.getAttributeValue(null, "delay");
+            if (val != null) {
+                long earliestRuntimeWallclock = Long.valueOf(val);
+                long minDelayElapsed =
+                        Math.max(earliestRuntimeWallclock - nowWallclock, 0);
+                earliestRunTimeElapsed = nowElapsed + minDelayElapsed;
+
+            }
+            return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
new file mode 100644
index 0000000..90c203a
--- /dev/null
+++ b/services/core/java/com/android/server/job/StateChangedListener.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.server.job;
+
+import com.android.server.job.controllers.JobStatus;
+
+/**
+ * Interface through which a {@link com.android.server.job.controllers.StateController} informs
+ * the {@link com.android.server.job.JobSchedulerService} that there are some tasks potentially
+ * ready to be run.
+ */
+public interface StateChangedListener {
+    /**
+     * Called by the controller to notify the JobManager that it should check on the state of a
+     * task.
+     */
+    public void onControllerStateChanged();
+
+    /**
+     * Called by the controller to notify the JobManager that regardless of the state of the task,
+     * it must be run immediately.
+     * @param jobStatus The state of the task which is to be run immediately.
+     */
+    public void onRunJobNow(JobStatus jobStatus);
+}
diff --git a/services/core/java/com/android/server/task/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
similarity index 80%
rename from services/core/java/com/android/server/task/controllers/BatteryController.java
rename to services/core/java/com/android/server/job/controllers/BatteryController.java
index 443527f..4aef2d31 100644
--- a/services/core/java/com/android/server/task/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -32,11 +32,12 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.BatteryService;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -45,7 +46,7 @@
  * ACTION_BATTERY_OK.
  */
 public class BatteryController extends StateController {
-    private static final String TAG = "BatteryController";
+    private static final String TAG = "JobScheduler.Batt";
 
     private static final Object sCreationLock = new Object();
     private static volatile BatteryController sController;
@@ -54,10 +55,10 @@
     /** Wait this long after phone is plugged in before doing any work. */
     private static final long STABLE_CHARGING_THRESHOLD_MILLIS = 2 * 60 * 1000; // 2 minutes.
 
-    private List<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+    private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     private ChargingTracker mChargeTracker;
 
-    public static BatteryController get(TaskManagerService taskManagerService) {
+    public static BatteryController get(JobSchedulerService taskManagerService) {
         synchronized (sCreationLock) {
             if (sController == null) {
                 sController = new BatteryController(taskManagerService,
@@ -85,18 +86,21 @@
     }
 
     @Override
-    public void maybeStartTrackingTask(TaskStatus taskStatus) {
+    public void maybeStartTrackingJob(JobStatus taskStatus) {
         if (taskStatus.hasChargingConstraint()) {
+            final boolean isOnStablePower = mChargeTracker.isOnStablePower();
             synchronized (mTrackedTasks) {
                 mTrackedTasks.add(taskStatus);
-                taskStatus.chargingConstraintSatisfied.set(mChargeTracker.isOnStablePower());
+                taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
+            }
+            if (isOnStablePower) {
+                mStateChangedListener.onControllerStateChanged();
             }
         }
-
     }
 
     @Override
-    public void maybeStopTrackingTask(TaskStatus taskStatus) {
+    public void maybeStopTrackingJob(JobStatus taskStatus) {
         if (taskStatus.hasChargingConstraint()) {
             synchronized (mTrackedTasks) {
                 mTrackedTasks.remove(taskStatus);
@@ -106,9 +110,12 @@
 
     private void maybeReportNewChargingState() {
         final boolean stablePower = mChargeTracker.isOnStablePower();
+        if (DEBUG) {
+            Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
+        }
         boolean reportChange = false;
         synchronized (mTrackedTasks) {
-            for (TaskStatus ts : mTrackedTasks) {
+            for (JobStatus ts : mTrackedTasks) {
                 boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
                 if (previous != stablePower) {
                     reportChange = true;
@@ -133,8 +140,7 @@
 
         public ChargingTracker() {
             mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-            Intent intent = new Intent(ACTION_CHARGING_STABLE)
-                    .setComponent(new ComponentName(mContext, this.getClass()));
+            Intent intent = new Intent(ACTION_CHARGING_STABLE);
             mStableChargingTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
         }
 
@@ -147,6 +153,8 @@
             // Charging/not charging.
             filter.addAction(Intent.ACTION_POWER_CONNECTED);
             filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+            // Charging stable.
+            filter.addAction(ACTION_CHARGING_STABLE);
             mContext.registerReceiver(this, filter);
 
             // Initialise tracker state.
@@ -189,6 +197,10 @@
                 mBatteryHealthy = true;
                 maybeReportNewChargingState();
             } else if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Received charging intent, setting alarm for "
+                            + STABLE_CHARGING_THRESHOLD_MILLIS);
+                }
                 // Set up an alarm for ACTION_CHARGING_STABLE - we don't want to kick off tasks
                 // here if the user unplugs the phone immediately.
                 mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
@@ -196,6 +208,9 @@
                         mStableChargingTriggerIntent);
                 mCharging = true;
             } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Disconnected from power, cancelling any set alarms.");
+                }
                 // If an alarm is set, breathe a sigh of relief and cancel it - crisis averted.
                 mAlarm.cancel(mStableChargingTriggerIntent);
                 mCharging = false;
@@ -203,7 +218,8 @@
             }else if (ACTION_CHARGING_STABLE.equals(action)) {
                 // Here's where we actually do the notify for a task being ready.
                 if (DEBUG) {
-                    Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime());
+                    Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime()
+                            + " charging: " + mCharging);
                 }
                 if (mCharging) {  // Should never receive this intent if mCharging is false.
                     maybeReportNewChargingState();
@@ -214,6 +230,17 @@
 
     @Override
     public void dumpControllerState(PrintWriter pw) {
-
+        pw.println("Batt.");
+        pw.println("Stable power: " + mChargeTracker.isOnStablePower());
+        synchronized (mTrackedTasks) {
+            Iterator<JobStatus> it = mTrackedTasks.iterator();
+            if (it.hasNext()) {
+                pw.print(String.valueOf(it.next().hashCode()));
+            }
+            while (it.hasNext()) {
+                pw.print("," + String.valueOf(it.next().hashCode()));
+            }
+            pw.println();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
similarity index 75%
rename from services/core/java/com/android/server/task/controllers/ConnectivityController.java
rename to services/core/java/com/android/server/job/controllers/ConnectivityController.java
index c1ab0f0..daba0d9 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
 
 
 import android.content.BroadcastReceiver;
@@ -28,8 +28,8 @@
 import android.util.Slog;
 
 import com.android.server.ConnectivityService;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
 import java.util.LinkedList;
@@ -42,9 +42,9 @@
  */
 public class ConnectivityController extends StateController implements
         ConnectivityManager.OnNetworkActiveListener {
-    private static final String TAG = "TaskManager.Conn";
+    private static final String TAG = "JobScheduler.Conn";
 
-    private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+    private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
     private final BroadcastReceiver mConnectivityChangedReceiver =
             new ConnectivityChangedReceiver();
     /** Singleton. */
@@ -55,10 +55,10 @@
     /** Track whether the latest active network is connected. */
     private boolean mNetworkConnected;
 
-    public static ConnectivityController get(TaskManagerService taskManager) {
+    public static ConnectivityController get(JobSchedulerService jms) {
         synchronized (sCreationLock) {
             if (mSingleton == null) {
-                mSingleton = new ConnectivityController(taskManager, taskManager.getContext());
+                mSingleton = new ConnectivityController(jms, jms.getContext());
             }
             return mSingleton;
         }
@@ -82,21 +82,21 @@
     }
 
     @Override
-    public void maybeStartTrackingTask(TaskStatus taskStatus) {
-        if (taskStatus.hasConnectivityConstraint() || taskStatus.hasUnmeteredConstraint()) {
-            synchronized (mTrackedTasks) {
-                taskStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
-                taskStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
-                mTrackedTasks.add(taskStatus);
+    public void maybeStartTrackingJob(JobStatus jobStatus) {
+        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+            synchronized (mTrackedJobs) {
+                jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
+                jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
+                mTrackedJobs.add(jobStatus);
             }
         }
     }
 
     @Override
-    public void maybeStopTrackingTask(TaskStatus taskStatus) {
-        if (taskStatus.hasConnectivityConstraint() || taskStatus.hasUnmeteredConstraint()) {
-            synchronized (mTrackedTasks) {
-                mTrackedTasks.remove(taskStatus);
+    public void maybeStopTrackingJob(JobStatus jobStatus) {
+        if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+            synchronized (mTrackedJobs) {
+                mTrackedJobs.remove(jobStatus);
             }
         }
     }
@@ -104,16 +104,16 @@
     /**
      * @param userId Id of the user for whom we are updating the connectivity state.
      */
-    private void updateTrackedTasks(int userId) {
-        synchronized (mTrackedTasks) {
+    private void updateTrackedJobs(int userId) {
+        synchronized (mTrackedJobs) {
             boolean changed = false;
-            for (TaskStatus ts : mTrackedTasks) {
-                if (ts.getUserId() != userId) {
+            for (JobStatus js : mTrackedJobs) {
+                if (js.getUserId() != userId) {
                     continue;
                 }
                 boolean prevIsConnected =
-                        ts.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
-                boolean prevIsMetered = ts.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
+                        js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
+                boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
                 if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
                     changed = true;
                 }
@@ -125,16 +125,16 @@
     }
 
     /**
-     * We know the network has just come up. We want to run any tasks that are ready.
+     * We know the network has just come up. We want to run any jobs that are ready.
      */
     public synchronized void onNetworkActive() {
-        synchronized (mTrackedTasks) {
-            for (TaskStatus ts : mTrackedTasks) {
-                if (ts.isReady()) {
+        synchronized (mTrackedJobs) {
+            for (JobStatus js : mTrackedJobs) {
+                if (js.isReady()) {
                     if (DEBUG) {
-                        Slog.d(TAG, "Running " + ts + " due to network activity.");
+                        Slog.d(TAG, "Running " + js + " due to network activity.");
                     }
-                    mStateChangedListener.onRunTaskNow(ts);
+                    mStateChangedListener.onRunJobNow(js);
                 }
             }
         }
@@ -169,7 +169,7 @@
                 if (activeNetwork == null) {
                     mNetworkUnmetered = false;
                     mNetworkConnected = false;
-                    updateTrackedTasks(userid);
+                    updateTrackedJobs(userid);
                 } else if (activeNetwork.getType() == networkType) {
                     mNetworkUnmetered = false;
                     mNetworkConnected = !intent.getBooleanExtra(
@@ -177,7 +177,7 @@
                     if (mNetworkConnected) {  // No point making the call if we know there's no conn.
                         mNetworkUnmetered = !connManager.isActiveNetworkMetered();
                     }
-                    updateTrackedTasks(userid);
+                    updateTrackedJobs(userid);
                 }
             } else {
                 if (DEBUG) {
@@ -191,10 +191,10 @@
     public void dumpControllerState(PrintWriter pw) {
         pw.println("Conn.");
         pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
-        for (TaskStatus ts: mTrackedTasks) {
-            pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
-                    + ": C=" + ts.hasConnectivityConstraint()
-                    + ", UM=" + ts.hasUnmeteredConstraint());
+        for (JobStatus js: mTrackedJobs) {
+            pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
+                    + ": C=" + js.hasConnectivityConstraint()
+                    + ", UM=" + js.hasUnmeteredConstraint());
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
similarity index 92%
rename from services/core/java/com/android/server/task/controllers/IdleController.java
rename to services/core/java/com/android/server/job/controllers/IdleController.java
index e749b00..07ffe4d 100644
--- a/services/core/java/com/android/server/task/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -29,8 +29,8 @@
 import android.os.SystemClock;
 import android.util.Slog;
 
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
 
 public class IdleController extends StateController {
     private static final String TAG = "IdleController";
@@ -43,14 +43,14 @@
     private static final String ACTION_TRIGGER_IDLE =
             "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
 
-    final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+    final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     IdlenessTracker mIdleTracker;
 
     // Singleton factory
     private static Object sCreationLock = new Object();
     private static volatile IdleController sController;
 
-    public static IdleController get(TaskManagerService service) {
+    public static IdleController get(JobSchedulerService service) {
         synchronized (sCreationLock) {
             if (sController == null) {
                 sController = new IdleController(service, service.getContext());
@@ -68,7 +68,7 @@
      * StateController interface
      */
     @Override
-    public void maybeStartTrackingTask(TaskStatus taskStatus) {
+    public void maybeStartTrackingJob(JobStatus taskStatus) {
         if (taskStatus.hasIdleConstraint()) {
             synchronized (mTrackedTasks) {
                 mTrackedTasks.add(taskStatus);
@@ -78,7 +78,7 @@
     }
 
     @Override
-    public void maybeStopTrackingTask(TaskStatus taskStatus) {
+    public void maybeStopTrackingJob(JobStatus taskStatus) {
         synchronized (mTrackedTasks) {
             mTrackedTasks.remove(taskStatus);
         }
@@ -89,7 +89,7 @@
      */
     void reportNewIdleState(boolean isIdle) {
         synchronized (mTrackedTasks) {
-            for (TaskStatus task : mTrackedTasks) {
+            for (JobStatus task : mTrackedTasks) {
                 task.idleConstraintSatisfied.set(isIdle);
             }
         }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
new file mode 100644
index 0000000..15a6b25
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -0,0 +1,217 @@
+/*
+ * 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.job.controllers;
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.os.PersistableBundle;
+import android.os.SystemClock;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Uniquely identifies a job internally.
+ * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
+ * Contains current state of the requirements of the job, as well as a function to evaluate
+ * whether it's ready to run.
+ * This object is shared among the various controllers - hence why the different fields are atomic.
+ * This isn't strictly necessary because each controller is only interested in a specific field,
+ * and the receivers that are listening for global state change will all run on the main looper,
+ * but we don't enforce that so this is safer.
+ * @hide
+ */
+public class JobStatus {
+    public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
+    public static final long NO_EARLIEST_RUNTIME = 0L;
+
+    final JobInfo job;
+    final int uId;
+
+    /** At reschedule time we need to know whether to update job on disk. */
+    final boolean persisted;
+
+    // Constraints.
+    final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
+
+    /**
+     * Earliest point in the future at which this job will be eligible to run. A value of 0
+     * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
+     */
+    private long earliestRunTimeElapsedMillis;
+    /**
+     * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
+     * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
+     */
+    private long latestRunTimeElapsedMillis;
+    /** How many times this job has failed, used to compute back-off. */
+    private final int numFailures;
+
+    /** Provide a handle to the service that this job will be run on. */
+    public int getServiceToken() {
+        return uId;
+    }
+
+    private JobStatus(JobInfo job, int uId, boolean persisted, int numFailures) {
+        this.job = job;
+        this.uId = uId;
+        this.numFailures = numFailures;
+        this.persisted = persisted;
+    }
+
+    /** Create a newly scheduled job. */
+    public JobStatus(JobInfo job, int uId, boolean persisted) {
+        this(job, uId, persisted, 0);
+
+        final long elapsedNow = SystemClock.elapsedRealtime();
+
+        if (job.isPeriodic()) {
+            earliestRunTimeElapsedMillis = elapsedNow;
+            latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
+        } else {
+            earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
+                    elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
+            latestRunTimeElapsedMillis = job.hasLateConstraint() ?
+                    elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
+        }
+    }
+
+    /**
+     * Create a new JobStatus that was loaded from disk. We ignore the provided
+     * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
+     * from the {@link com.android.server.job.JobStore} and still want to respect its
+     * wallclock runtime rather than resetting it on every boot.
+     * We consider a freshly loaded job to no longer be in back-off.
+     */
+    public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis,
+                      long latestRunTimeElapsedMillis) {
+        this(job, uId, true, 0);
+
+        this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
+        this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
+    }
+
+    /** Create a new job to be rescheduled with the provided parameters. */
+    public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
+                      long newLatestRuntimeElapsedMillis, int backoffAttempt) {
+        this(rescheduling.job, rescheduling.getUid(), rescheduling.isPersisted(), backoffAttempt);
+
+        earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
+        latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
+    }
+
+    public JobInfo getJob() {
+        return job;
+    }
+
+    public int getJobId() {
+        return job.getId();
+    }
+
+    public int getNumFailures() {
+        return numFailures;
+    }
+
+    public ComponentName getServiceComponent() {
+        return job.getService();
+    }
+
+    public int getUserId() {
+        return UserHandle.getUserId(uId);
+    }
+
+    public int getUid() {
+        return uId;
+    }
+
+    public PersistableBundle getExtras() {
+        return job.getExtras();
+    }
+
+    public boolean hasConnectivityConstraint() {
+        return job.getNetworkCapabilities() == JobInfo.NetworkType.ANY;
+    }
+
+    public boolean hasUnmeteredConstraint() {
+        return job.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED;
+    }
+
+    public boolean hasChargingConstraint() {
+        return job.isRequireCharging();
+    }
+
+    public boolean hasTimingDelayConstraint() {
+        return earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME;
+    }
+
+    public boolean hasDeadlineConstraint() {
+        return latestRunTimeElapsedMillis != NO_LATEST_RUNTIME;
+    }
+
+    public boolean hasIdleConstraint() {
+        return job.isRequireDeviceIdle();
+    }
+
+    public long getEarliestRunTime() {
+        return earliestRunTimeElapsedMillis;
+    }
+
+    public long getLatestRunTimeElapsed() {
+        return latestRunTimeElapsedMillis;
+    }
+
+    public boolean isPersisted() {
+        return persisted;
+    }
+    /**
+     * @return Whether or not this job is ready to run, based on its requirements.
+     */
+    public synchronized boolean isReady() {
+        return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
+                && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
+                && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
+                && (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
+                && (!hasIdleConstraint() || idleConstraintSatisfied.get())
+                // Also ready if the deadline has expired - special case.
+                || (hasDeadlineConstraint() && deadlineConstraintSatisfied.get());
+    }
+
+    public boolean matches(int uid, int jobId) {
+        return this.job.getId() == jobId && this.uId == uid;
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(hashCode()).substring(0, 3) + ".."
+                + ":[" + job.getService().getPackageName() + ",jId=" + job.getId()
+                + ",R=(" + earliestRunTimeElapsedMillis + "," + latestRunTimeElapsedMillis + ")"
+                + ",N=" + job.getNetworkCapabilities() + ",C=" + job.isRequireCharging()
+                + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
+                + (isReady() ? "(READY)" : "")
+                + "]";
+    }
+    // Dumpsys infrastructure
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(this.toString());
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
similarity index 70%
rename from services/core/java/com/android/server/task/controllers/StateController.java
rename to services/core/java/com/android/server/job/controllers/StateController.java
index a7f52f5..81658bf 100644
--- a/services/core/java/com/android/server/task/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -14,18 +14,18 @@
  * limitations under the License
  */
 
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
 
 import android.content.Context;
 
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
 
 /**
- * Incorporates shared controller logic between the various controllers of the TaskManager.
- * These are solely responsible for tracking a list of tasks, and notifying the TM when these
+ * Incorporates shared controller logic between the various controllers of the JobManager.
+ * These are solely responsible for tracking a list of jobs, and notifying the JM when these
  * are ready to run, or whether they must be stopped.
  */
 public abstract class StateController {
@@ -39,16 +39,16 @@
     }
 
     /**
-     * Implement the logic here to decide whether a task should be tracked by this controller.
-     * This logic is put here so the TaskManger can be completely agnostic of Controller logic.
+     * Implement the logic here to decide whether a job should be tracked by this controller.
+     * This logic is put here so the JobManger can be completely agnostic of Controller logic.
      * Also called when updating a task, so implementing controllers have to be aware of
      * preexisting tasks.
      */
-    public abstract void maybeStartTrackingTask(TaskStatus taskStatus);
+    public abstract void maybeStartTrackingJob(JobStatus jobStatus);
     /**
      * Remove task - this will happen if the task is cancelled, completed, etc.
      */
-    public abstract void maybeStopTrackingTask(TaskStatus taskStatus);
+    public abstract void maybeStopTrackingJob(JobStatus jobStatus);
 
     public abstract void dumpControllerState(PrintWriter pw);
 
diff --git a/services/core/java/com/android/server/task/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
similarity index 61%
rename from services/core/java/com/android/server/task/controllers/TimeController.java
rename to services/core/java/com/android/server/job/controllers/TimeController.java
index b75036c..e46226c 100644
--- a/services/core/java/com/android/server/task/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -25,8 +25,8 @@
 import android.os.SystemClock;
 import android.util.Slog;
 
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
 import java.util.Iterator;
@@ -35,35 +35,35 @@
 import java.util.ListIterator;
 
 /**
- * This class sets an alarm for the next expiring task, and determines whether a task's minimum
+ * This class sets an alarm for the next expiring job, and determines whether a job's minimum
  * delay has been satisfied.
  */
 public class TimeController extends StateController {
-    private static final String TAG = "TaskManager.Time";
-    private static final String ACTION_TASK_EXPIRED =
-            "android.content.taskmanager.TASK_DEADLINE_EXPIRED";
-    private static final String ACTION_TASK_DELAY_EXPIRED =
-            "android.content.taskmanager.TASK_DELAY_EXPIRED";
+    private static final String TAG = "JobScheduler.Time";
+    private static final String ACTION_JOB_EXPIRED =
+            "android.content.jobscheduler.JOB_DEADLINE_EXPIRED";
+    private static final String ACTION_JOB_DELAY_EXPIRED =
+            "android.content.jobscheduler.JOB_DELAY_EXPIRED";
 
-    /** Set an alarm for the next task expiry. */
+    /** Set an alarm for the next job expiry. */
     private final PendingIntent mDeadlineExpiredAlarmIntent;
-    /** Set an alarm for the next task delay expiry. This*/
+    /** Set an alarm for the next job delay expiry. This*/
     private final PendingIntent mNextDelayExpiredAlarmIntent;
     /** Constant time determining how near in the future we'll set an alarm for. */
     private static final long MIN_WAKEUP_INTERVAL_MILLIS = 15 * 1000;
 
-    private long mNextTaskExpiredElapsedMillis;
+    private long mNextJobExpiredElapsedMillis;
     private long mNextDelayExpiredElapsedMillis;
 
     private AlarmManager mAlarmService = null;
-    /** List of tracked tasks, sorted asc. by deadline */
-    private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+    /** List of tracked jobs, sorted asc. by deadline */
+    private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
     /** Singleton. */
     private static TimeController mSingleton;
 
-    public static synchronized TimeController get(TaskManagerService taskManager) {
+    public static synchronized TimeController get(JobSchedulerService jms) {
         if (mSingleton == null) {
-            mSingleton = new TimeController(taskManager, taskManager.getContext());
+            mSingleton = new TimeController(jms, jms.getContext());
         }
         return mSingleton;
     }
@@ -72,66 +72,66 @@
         super(stateChangedListener, context);
         mDeadlineExpiredAlarmIntent =
                 PendingIntent.getBroadcast(mContext, 0 /* ignored */,
-                        new Intent(ACTION_TASK_EXPIRED), 0);
+                        new Intent(ACTION_JOB_EXPIRED), 0);
         mNextDelayExpiredAlarmIntent =
                 PendingIntent.getBroadcast(mContext, 0 /* ignored */,
-                        new Intent(ACTION_TASK_DELAY_EXPIRED), 0);
-        mNextTaskExpiredElapsedMillis = Long.MAX_VALUE;
+                        new Intent(ACTION_JOB_DELAY_EXPIRED), 0);
+        mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
         mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
 
         // Register BR for these intents.
-        IntentFilter intentFilter = new IntentFilter(ACTION_TASK_EXPIRED);
-        intentFilter.addAction(ACTION_TASK_DELAY_EXPIRED);
+        IntentFilter intentFilter = new IntentFilter(ACTION_JOB_EXPIRED);
+        intentFilter.addAction(ACTION_JOB_DELAY_EXPIRED);
         mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
     }
 
     /**
-     * Check if the task has a timing constraint, and if so determine where to insert it in our
+     * Check if the job has a timing constraint, and if so determine where to insert it in our
      * list.
      */
     @Override
-    public synchronized void maybeStartTrackingTask(TaskStatus task) {
-        if (task.hasTimingDelayConstraint() || task.hasDeadlineConstraint()) {
-            maybeStopTrackingTask(task);
-            ListIterator<TaskStatus> it = mTrackedTasks.listIterator(mTrackedTasks.size());
+    public synchronized void maybeStartTrackingJob(JobStatus job) {
+        if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
+            maybeStopTrackingJob(job);
+            ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
             while (it.hasPrevious()) {
-                TaskStatus ts = it.previous();
-                if (ts.getLatestRunTimeElapsed() < task.getLatestRunTimeElapsed()) {
+                JobStatus ts = it.previous();
+                if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
                     // Insert
                     break;
                 }
             }
-            it.add(task);
+            it.add(job);
             maybeUpdateAlarms(
-                    task.hasTimingDelayConstraint() ? task.getEarliestRunTime() : Long.MAX_VALUE,
-                    task.hasDeadlineConstraint() ? task.getLatestRunTimeElapsed() : Long.MAX_VALUE);
+                    job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
+                    job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
         }
     }
 
     /**
-     * When we stop tracking a task, we only need to update our alarms if the task we're no longer
+     * When we stop tracking a job, we only need to update our alarms if the job we're no longer
      * tracking was the one our alarms were based off of.
      * Really an == comparison should be enough, but why play with fate? We'll do <=.
      */
     @Override
-    public synchronized void maybeStopTrackingTask(TaskStatus taskStatus) {
-        if (mTrackedTasks.remove(taskStatus)) {
+    public synchronized void maybeStopTrackingJob(JobStatus job) {
+        if (mTrackedJobs.remove(job)) {
             checkExpiredDelaysAndResetAlarm();
             checkExpiredDeadlinesAndResetAlarm();
         }
     }
 
     /**
-     * Determines whether this controller can stop tracking the given task.
-     * The controller is no longer interested in a task once its time constraint is satisfied, and
-     * the task's deadline is fulfilled - unlike other controllers a time constraint can't toggle
+     * Determines whether this controller can stop tracking the given job.
+     * The controller is no longer interested in a job once its time constraint is satisfied, and
+     * the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
      * back and forth.
      */
-    private boolean canStopTrackingTask(TaskStatus taskStatus) {
-        return (!taskStatus.hasTimingDelayConstraint() ||
-                taskStatus.timeDelayConstraintSatisfied.get()) &&
-                (!taskStatus.hasDeadlineConstraint() ||
-                        taskStatus.deadlineConstraintSatisfied.get());
+    private boolean canStopTrackingJob(JobStatus job) {
+        return (!job.hasTimingDelayConstraint() ||
+                job.timeDelayConstraintSatisfied.get()) &&
+                (!job.hasDeadlineConstraint() ||
+                        job.deadlineConstraintSatisfied.get());
     }
 
     private void ensureAlarmService() {
@@ -141,27 +141,27 @@
     }
 
     /**
-     * Checks list of tasks for ones that have an expired deadline, sending them to the TaskManager
+     * Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
      * if so, removing them from this list, and updating the alarm for the next expiry time.
      */
     private synchronized void checkExpiredDeadlinesAndResetAlarm() {
         long nextExpiryTime = Long.MAX_VALUE;
         final long nowElapsedMillis = SystemClock.elapsedRealtime();
 
-        Iterator<TaskStatus> it = mTrackedTasks.iterator();
+        Iterator<JobStatus> it = mTrackedJobs.iterator();
         while (it.hasNext()) {
-            TaskStatus ts = it.next();
-            if (!ts.hasDeadlineConstraint()) {
+            JobStatus job = it.next();
+            if (!job.hasDeadlineConstraint()) {
                 continue;
             }
-            final long taskDeadline = ts.getLatestRunTimeElapsed();
+            final long jobDeadline = job.getLatestRunTimeElapsed();
 
-            if (taskDeadline <= nowElapsedMillis) {
-                ts.deadlineConstraintSatisfied.set(true);
-                mStateChangedListener.onRunTaskNow(ts);
+            if (jobDeadline <= nowElapsedMillis) {
+                job.deadlineConstraintSatisfied.set(true);
+                mStateChangedListener.onRunJobNow(job);
                 it.remove();
             } else {  // Sorted by expiry time, so take the next one and stop.
-                nextExpiryTime = taskDeadline;
+                nextExpiryTime = jobDeadline;
                 break;
             }
         }
@@ -169,31 +169,31 @@
     }
 
     /**
-     * Handles alarm that notifies us that a task's delay has expired. Iterates through the list of
-     * tracked tasks and marks them as ready as appropriate.
+     * Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
+     * tracked jobs and marks them as ready as appropriate.
      */
     private synchronized void checkExpiredDelaysAndResetAlarm() {
         final long nowElapsedMillis = SystemClock.elapsedRealtime();
         long nextDelayTime = Long.MAX_VALUE;
         boolean ready = false;
-        Iterator<TaskStatus> it = mTrackedTasks.iterator();
+        Iterator<JobStatus> it = mTrackedJobs.iterator();
         while (it.hasNext()) {
-            final TaskStatus ts = it.next();
-            if (!ts.hasTimingDelayConstraint()) {
+            final JobStatus job = it.next();
+            if (!job.hasTimingDelayConstraint()) {
                 continue;
             }
-            final long taskDelayTime = ts.getEarliestRunTime();
-            if (taskDelayTime <= nowElapsedMillis) {
-                ts.timeDelayConstraintSatisfied.set(true);
-                if (canStopTrackingTask(ts)) {
+            final long jobDelayTime = job.getEarliestRunTime();
+            if (jobDelayTime <= nowElapsedMillis) {
+                job.timeDelayConstraintSatisfied.set(true);
+                if (canStopTrackingJob(job)) {
                     it.remove();
                 }
-                if (ts.isReady()) {
+                if (job.isReady()) {
                     ready = true;
                 }
             } else {  // Keep going through list to get next delay time.
-                if (nextDelayTime > taskDelayTime) {
-                    nextDelayTime = taskDelayTime;
+                if (nextDelayTime > jobDelayTime) {
+                    nextDelayTime = jobDelayTime;
                 }
             }
         }
@@ -207,13 +207,13 @@
         if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
             setDelayExpiredAlarm(delayExpiredElapsed);
         }
-        if (deadlineExpiredElapsed < mNextTaskExpiredElapsedMillis) {
+        if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
             setDeadlineExpiredAlarm(deadlineExpiredElapsed);
         }
     }
 
     /**
-     * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+     * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
      * delay will expire.
      * This alarm <b>will not</b> wake up the phone.
      */
@@ -228,7 +228,7 @@
     }
 
     /**
-     * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+     * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
      * deadline will expire.
      * This alarm <b>will</b> wake up the phone.
      */
@@ -238,8 +238,8 @@
         if (alarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
             alarmTimeElapsedMillis = earliestWakeupTimeElapsed;
         }
-        mNextTaskExpiredElapsedMillis = alarmTimeElapsedMillis;
-        updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextTaskExpiredElapsedMillis);
+        mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
+        updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextJobExpiredElapsedMillis);
     }
 
     private void updateAlarmWithPendingIntent(PendingIntent pi, long alarmTimeElapsed) {
@@ -260,11 +260,11 @@
             if (DEBUG) {
                 Slog.d(TAG, "Just received alarm: " + intent.getAction());
             }
-            // An task has just expired, so we run through the list of tasks that we have and
+            // A job has just expired, so we run through the list of jobs that we have and
             // notify our StateChangedListener.
-            if (ACTION_TASK_EXPIRED.equals(intent.getAction())) {
+            if (ACTION_JOB_EXPIRED.equals(intent.getAction())) {
                 checkExpiredDeadlinesAndResetAlarm();
-            } else if (ACTION_TASK_DELAY_EXPIRED.equals(intent.getAction())) {
+            } else if (ACTION_JOB_DELAY_EXPIRED.equals(intent.getAction())) {
                 checkExpiredDelaysAndResetAlarm();
             }
         }
@@ -276,10 +276,10 @@
         pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
         pw.println(
                 "Next delay alarm in " + (mNextDelayExpiredElapsedMillis - nowElapsed)/1000 + "s");
-        pw.println("Next deadline alarm in " + (mNextTaskExpiredElapsedMillis - nowElapsed)/1000
+        pw.println("Next deadline alarm in " + (mNextJobExpiredElapsedMillis - nowElapsed)/1000
                 + "s");
         pw.println("Tracking:");
-        for (TaskStatus ts : mTrackedTasks) {
+        for (JobStatus ts : mTrackedJobs) {
             pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
                     + ": (" + (ts.hasTimingDelayConstraint() ? ts.getEarliestRunTime() : "N/A")
                     + ", " + (ts.hasDeadlineConstraint() ?ts.getLatestRunTimeElapsed() : "N/A")
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 835b094..9ae8aed 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -949,6 +949,11 @@
         }
 
         @Override
+        public long getFlags() {
+            return mFlags;
+        }
+
+        @Override
         public void play() throws RemoteException {
             mSessionCb.play();
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 386402b..825dc84 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -188,6 +188,8 @@
 
     private AppOpsManager mAppOps;
 
+    private Archive mArchive;
+
     // Notification control database. For now just contains disabled packages.
     private AtomicFile mPolicyFile;
     private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -223,10 +225,12 @@
     private static final int REASON_LISTENER_CANCEL_ALL = 11;
 
     private static class Archive {
-        static final int BUFFER_SIZE = 250;
-        ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
+        final int mBufferSize;
+        final ArrayDeque<StatusBarNotification> mBuffer;
 
-        public Archive() {
+        public Archive(int size) {
+            mBufferSize = size;
+            mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
         }
 
         public String toString() {
@@ -240,7 +244,7 @@
         }
 
         public void record(StatusBarNotification nr) {
-            if (mBuffer.size() == BUFFER_SIZE) {
+            if (mBuffer.size() == mBufferSize) {
                 mBuffer.removeFirst();
             }
 
@@ -250,7 +254,6 @@
             mBuffer.addLast(nr.cloneLight());
         }
 
-
         public void clear() {
             mBuffer.clear();
         }
@@ -300,7 +303,7 @@
         }
 
         public StatusBarNotification[] getArray(int count) {
-            if (count == 0) count = Archive.BUFFER_SIZE;
+            if (count == 0) count = mBufferSize;
             final StatusBarNotification[] a
                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
             Iterator<StatusBarNotification> iter = descendingIterator();
@@ -312,7 +315,7 @@
         }
 
         public StatusBarNotification[] getArray(int count, String pkg, int userId) {
-            if (count == 0) count = Archive.BUFFER_SIZE;
+            if (count == 0) count = mBufferSize;
             final StatusBarNotification[] a
                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
             Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
@@ -325,8 +328,6 @@
 
     }
 
-    Archive mArchive = new Archive();
-
     private void loadPolicyFile() {
         synchronized(mPolicyFile) {
             mBlockedPackages.clear();
@@ -854,6 +855,9 @@
             }
         }
 
+        mArchive = new Archive(resources.getInteger(
+                R.integer.config_notificationServiceArchiveSize));
+
         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
         publishLocalService(NotificationManagerInternal.class, mInternalService);
     }
@@ -2264,16 +2268,15 @@
 
     // lock on mNotificationList
     int indexOfNotificationLocked(String key) {
-        NotificationRecord r = mNotificationsByKey.get(key);
-        if (r == null) {
-            return -1;
+        final int N = mNotificationList.size();
+        for (int i = 0; i < N; i++) {
+            if (key.equals(mNotificationList.get(i).getKey())) {
+                return i;
+            }
         }
-        int index = Collections.binarySearch(mNotificationList, r, mRankingComparator);
-        // Guarantee to return -1 when not found.
-        return (index >= 0) ? index : -1;
+        return -1;
     }
 
-
     private void updateNotificationPulse() {
         synchronized (mNotificationList) {
             updateLightsLocked();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 50a32c4..b95db9c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -18,6 +18,7 @@
 
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
+import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -88,6 +89,10 @@
     private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList(
             "com.google.android.deskclock"
             ));
+    private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList(
+            "android",
+            "com.android.systemui"
+            ));
 
     public ZenModeHelper(Context context, Handler handler) {
         mContext = context;
@@ -130,6 +135,9 @@
                 // notifications never transition from not intercepted to intercepted
                 return false;
             }
+            if (isSystem(record)) {
+                return false;
+            }
             if (isAlarm(record)) {
                 return false;
             }
@@ -239,6 +247,11 @@
         }
     }
 
+    private boolean isSystem(NotificationRecord record) {
+        return SYSTEM_PACKAGES.contains(record.sbn.getPackageName())
+                && Notification.CATEGORY_SYSTEM.equals(record.getNotification().category);
+    }
+
     private boolean isAlarm(NotificationRecord record) {
         return ALARM_PACKAGES.contains(record.sbn.getPackageName());
     }
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index f2db791..2a7b4f6 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,12 +16,13 @@
 
 package com.android.server.pm;
 
-import android.content.BroadcastReceiver;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
 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;
@@ -30,62 +31,63 @@
 /**
  * {@hide}
  */
-public class BackgroundDexOptService {
-
+public class BackgroundDexOptService extends JobService {
     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;
+    static final int BACKGROUND_DEXOPT_JOB = 808;
+    private static ComponentName sDexoptServiceName = new ComponentName(
+            BackgroundDexOptService.class.getPackage().getName(),
+            BackgroundDexOptService.class.getName());
 
     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 static void schedule(Context context) {
+        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
+                .setRequiresDeviceIdle(true)
+                .setRequiresCharging(true)
+                .build();
+        js.schedule(job);
     }
 
-    public boolean onIdleStart() {
+    @Override
+    public boolean onStartJob(JobParameters params) {
         Log.i(TAG, "onIdleStart");
-        if (mPackageManager.isStorageLow()) {
+        final PackageManagerService pm =
+                (PackageManagerService)ServiceManager.getService("package");
+
+        if (pm.isStorageLow()) {
             return false;
         }
-        final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+        final HashSet<String> pkgs = pm.getPackagesThatNeedDexOpt();
         if (pkgs == null) {
             return false;
         }
+
+        final JobParameters jobParams = params;
         mIdleTime.set(true);
         new Thread("BackgroundDexOptService_DexOpter") {
             @Override
             public void run() {
                 for (String pkg : pkgs) {
                     if (!mIdleTime.get()) {
-                        break;
+                        // stopped while still working, so we need to reschedule
+                        schedule(BackgroundDexOptService.this);
+                        return;
                     }
-                    mPackageManager.performDexOpt(pkg, false);
+                    pm.performDexOpt(pkg, false);
                 }
+                // ran to completion, so we abandon our timeslice and do not reschedule
+                jobFinished(jobParams, false);
             }
         }.start();
         return true;
     }
 
-    public void onIdleStop() {
+    @Override
+    public boolean onStopJob(JobParameters params) {
         Log.i(TAG, "onIdleStop");
         mIdleTime.set(false);
+        return false;
     }
 }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 82d3f53..c0f1eec 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -345,6 +345,10 @@
         }
     }
 
+    public int pruneDexCache() {
+        return execute("prunedexcache");
+    }
+
     public int freeCache(long freeStorageSize) {
         StringBuilder builder = new StringBuilder("freecache");
         builder.append(' ');
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ed73f7..dd33771 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -28,7 +28,7 @@
 import android.content.pm.PackageInstallerParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.Signature;
 import android.os.Build;
 import android.os.Bundle;
@@ -297,7 +297,7 @@
 
         // Verify that all staged packages are internally consistent
         for (File file : files) {
-            final PackageLite info = PackageParser.parsePackageLite(file.getAbsolutePath(),
+            final ApkLite info = PackageParser.parseApkLite(file.getAbsolutePath(),
                     PackageParser.PARSE_GET_SIGNATURES);
             if (info == null) {
                 throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
@@ -356,7 +356,7 @@
                         "Missing existing base package for " + mPackageName);
             }
 
-            final PackageLite info = PackageParser.parsePackageLite(app.sourceDir,
+            final ApkLite info = PackageParser.parseApkLite(app.sourceDir,
                     PackageParser.PARSE_GET_SIGNATURES);
             if (info == null) {
                 throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8585b4e..8d94396 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -93,6 +93,7 @@
 import android.content.pm.PackageInstallerParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
@@ -136,6 +137,7 @@
 import android.system.Os;
 import android.system.StructStat;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -412,9 +414,6 @@
     final HashMap<String, SharedLibraryEntry> mSharedLibraries
             = new HashMap<String, SharedLibraryEntry>();
 
-    // Temporary for building the final shared libraries for an .apk.
-    String[] mTmpSharedLibraries = null;
-
     // These are the features this devices supports that were read from the
     // etc/permissions.xml file.
     final HashMap<String, FeatureInfo> mAvailableFeatures =
@@ -1485,7 +1484,21 @@
             }
 
             if (didDexOptLibraryOrTool) {
-                pruneDexFiles(new File(dataDir, "dalvik-cache"));
+                // If we dexopted a library or tool, then something on the system has
+                // changed. Consider this significant, and wipe away all other
+                // existing dexopt files to ensure we don't leave any dangling around.
+                //
+                // Additionally, delete all dex files from the root directory
+                // since there shouldn't be any there anyway.
+                //
+                // TODO: This should be revisited because it 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.
+                mInstaller.pruneDexCache();
             }
 
             // Collect vendor overlay packages.
@@ -1727,45 +1740,6 @@
         Runtime.getRuntime().gc();
     }
 
-    private static void pruneDexFiles(File cacheDir) {
-        // If we had to do a dexopt of one of the previous
-        // things, then something on the system has changed.
-        // Consider this significant, and wipe away all other
-        // existing dexopt files to ensure we don't leave any
-        // dangling around.
-        //
-        // 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) {
-                if (!file.isDirectory()) {
-                    Slog.i(TAG, "Pruning dalvik file: " + file.getAbsolutePath());
-                    file.delete();
-                } else {
-                    File[] subDirList = file.listFiles();
-                    if (subDirList != null) {
-                        for (File subDirFile : subDirList) {
-                            final String fn = subDirFile.getName();
-                            if (fn.startsWith("data@app@") || fn.startsWith("data@app-private@")) {
-                                Slog.i(TAG, "Pruning dalvik file: " + fn);
-                                subDirFile.delete();
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     @Override
     public boolean isFirstBoot() {
         return !mRestoredSettings || mPackageUsage.isFirstBoot();
@@ -2268,8 +2242,7 @@
                 if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
                     return null;
                 }
-                // TODO: teach about reading split name
-                pkg = new PackageParser.Package(packageName, null);
+                pkg = new PackageParser.Package(packageName);
                 pkg.applicationInfo.packageName = packageName;
                 pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
                 pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
@@ -4097,19 +4070,19 @@
     private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
             PackageParser.Package opkg) {
         if (!opkg.mTrustedOverlay) {
-            Slog.w(TAG, "Skipping target and overlay pair " + pkg.mScanPath + " and " +
-                    opkg.mScanPath + ": overlay not trusted");
+            Slog.w(TAG, "Skipping target and overlay pair " + pkg.codePath + " and " +
+                    opkg.codePath + ": overlay not trusted");
             return false;
         }
         HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
         if (overlaySet == null) {
-            Slog.e(TAG, "was about to create idmap for " + pkg.mScanPath + " and " +
-                    opkg.mScanPath + " but target package has no known overlays");
+            Slog.e(TAG, "was about to create idmap for " + pkg.codePath + " and " +
+                    opkg.codePath + " but target package has no known overlays");
             return false;
         }
         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-        if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) {
-            Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath);
+        if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) {
+            Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath);
             return false;
         }
         PackageParser.Package[] overlayArray =
@@ -4204,8 +4177,10 @@
             Log.i(TAG, srcFile.toString() + " changed; collecting certs");
         }
 
-        if (!pp.collectCertificates(pkg, parseFlags)) {
-            mLastScanError = pp.getParseError();
+        try {
+            pp.collectCertificates(pkg, parseFlags);
+        } catch (PackageParserException e) {
+            mLastScanError = e.error;
             return false;
         }
         return true;
@@ -4224,11 +4199,13 @@
         PackageParser pp = new PackageParser(scanPath);
         pp.setSeparateProcesses(mSeparateProcesses);
         pp.setOnlyCoreApps(mOnlyCore);
-        final PackageParser.Package pkg = pp.parsePackage(scanFile,
-                scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
 
-        if (pkg == null) {
-            mLastScanError = pp.getParseError();
+        final PackageParser.Package pkg;
+        try {
+            pkg = pp.parseMonolithicPackage(scanFile, mMetrics, parseFlags,
+                (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
+        } catch (PackageParserException e) {
+            mLastScanError = e.error;
             return null;
         }
 
@@ -4395,12 +4372,13 @@
                 Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
             }
         } else {
-            resPath = pkg.mScanPath;
+            resPath = pkg.codePath;
         }
 
-        codePath = pkg.mScanPath;
+        codePath = pkg.codePath;
         // Set application objects path explicitly.
-        setApplicationInfoPaths(pkg, codePath, resPath);
+        pkg.applicationInfo.sourceDir = codePath;
+        pkg.applicationInfo.publicSourceDir = resPath;
         // Note that we invoke the following method only if we are about to unpack an application
         PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
                 | SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride);
@@ -4425,13 +4403,6 @@
         return scannedPkg;
     }
 
-    private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath,
-            String destResPath) {
-        pkg.mPath = pkg.mScanPath = destCodePath;
-        pkg.applicationInfo.sourceDir = destCodePath;
-        pkg.applicationInfo.publicSourceDir = destResPath;
-    }
-
     private static String fixProcessName(String defProcessName,
             String processName, int uid) {
         if (processName == null) {
@@ -4657,7 +4628,7 @@
 
         boolean performed = false;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            String path = pkg.mScanPath;
+            String path = pkg.codePath;
             try {
                 boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
                                                                                 pkg.packageName,
@@ -4830,11 +4801,11 @@
         return res;
     }
 
-    private int addSharedLibraryLPw(final SharedLibraryEntry file, int num,
+    private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
             PackageParser.Package changingLib) {
         if (file.path != null) {
-            mTmpSharedLibraries[num] = file.path;
-            return num+1;
+            usesLibraryFiles.add(file.path);
+            return;
         }
         PackageParser.Package p = mPackages.get(file.apk);
         if (changingLib != null && changingLib.packageName.equals(file.apk)) {
@@ -4847,16 +4818,8 @@
             }
         }
         if (p != null) {
-            String path = p.mPath;
-            for (int i=0; i<num; i++) {
-                if (mTmpSharedLibraries[i].equals(path)) {
-                    return num;
-                }
-            }
-            mTmpSharedLibraries[num] = p.mPath;
-            return num+1;
+            usesLibraryFiles.add(p.codePath);
         }
-        return num;
     }
 
     private boolean updateSharedLibrariesLPw(PackageParser.Package pkg,
@@ -4870,11 +4833,7 @@
         }
 
         if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
-            if (mTmpSharedLibraries == null ||
-                    mTmpSharedLibraries.length < mSharedLibraries.size()) {
-                mTmpSharedLibraries = new String[mSharedLibraries.size()];
-            }
-            int num = 0;
+            final ArraySet<String> usesLibraryFiles = new ArraySet<>();
             int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
             for (int i=0; i<N; i++) {
                 final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i));
@@ -4885,7 +4844,7 @@
                     mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
                     return false;
                 }
-                num = addSharedLibraryLPw(file, num, changingLib);
+                addSharedLibraryLPw(usesLibraryFiles, file, changingLib);
             }
             N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
             for (int i=0; i<N; i++) {
@@ -4895,13 +4854,12 @@
                             + " desires unavailable shared library "
                             + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
                 } else {
-                    num = addSharedLibraryLPw(file, num, changingLib);
+                    addSharedLibraryLPw(usesLibraryFiles, file, changingLib);
                 }
             }
-            if (num > 0) {
-                pkg.usesLibraryFiles = new String[num];
-                System.arraycopy(mTmpSharedLibraries, 0,
-                        pkg.usesLibraryFiles, 0, num);
+            N = usesLibraryFiles.size();
+            if (N > 0) {
+                pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]);
             } else {
                 pkg.usesLibraryFiles = null;
             }
@@ -4947,7 +4905,7 @@
 
     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
             int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
-        File scanFile = new File(pkg.mScanPath);
+        final File scanFile = new File(pkg.codePath);
         if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
                 pkg.applicationInfo.publicSourceDir == null) {
             // Bail out. The resource and code paths haven't been set.
@@ -4991,6 +4949,7 @@
                     mResolveActivity.packageName = mAndroidApplication.packageName;
                     mResolveActivity.processName = "system:ui";
                     mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                    mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
                     mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                     mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
                     mResolveActivity.exported = true;
@@ -5384,7 +5343,7 @@
             pkgSetting.uidError = uidError;
         }
 
-        String path = scanFile.getPath();
+        final String path = scanFile.getPath();
         /* Note: We don't want to unpack the native binaries for
          *        system applications, unless they have been updated
          *        (the binaries are already under /system/lib).
@@ -5515,7 +5474,6 @@
                 handle.close();
             }
         }
-        pkg.mScanPath = path;
 
         if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
             // We don't do this here during boot because we can do it all
@@ -5660,7 +5618,7 @@
         synchronized (mPackages) {
             // We don't expect installation to fail beyond this point,
             if ((scanMode&SCAN_MONITOR) != 0) {
-                mAppDirs.put(pkg.mPath, pkg);
+                mAppDirs.put(pkg.codePath, pkg);
             }
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLPw(pkgSetting, pkg);
@@ -6281,8 +6239,8 @@
         // writer
         synchronized (mPackages) {
             mPackages.remove(pkg.applicationInfo.packageName);
-            if (pkg.mPath != null) {
-                mAppDirs.remove(pkg.mPath);
+            if (pkg.codePath != null) {
+                mAppDirs.remove(pkg.codePath);
             }
             cleanPackageDataStructuresLILPw(pkg, chatty);
         }
@@ -9849,7 +9807,7 @@
                 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                 return;
             }
-            if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
+            if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.codePath)) {
                 // Don't allow installation over an existing package with the same name.
                 Slog.w(TAG, "Attempt to re-install " + pkgName
                         + " without first uninstalling.");
@@ -9861,15 +9819,12 @@
         PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
                 System.currentTimeMillis(), user, abiOverride);
         if (newPackage == null) {
-            Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+            Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
             }
         } else {
-            updateSettingsLI(newPackage,
-                    installerPackageName,
-                    null, null,
-                    res);
+            updateSettingsLI(newPackage, installerPackageName, null, null, res);
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -9954,15 +9909,12 @@
             newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
                     System.currentTimeMillis(), user, abiOverride);
             if (newPackage == null) {
-                Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+                Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
                 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                     res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
                 }
             } else {
-                updateSettingsLI(newPackage,
-                        installerPackageName,
-                        allUsers, perUserInstalled,
-                        res);
+                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
                 updatedSettings = true;
             }
         }
@@ -9983,7 +9935,7 @@
             // package that we deleted.
             if (deletedPkg) {
                 if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
-                File restoreFile = new File(deletedPackage.mPath);
+                File restoreFile = new File(deletedPackage.codePath);
                 // Parse old package
                 boolean oldOnSd = isExternal(deletedPackage);
                 int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
@@ -10068,7 +10020,7 @@
         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user, abiOverride);
         if (newPackage == null) {
-            Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+            Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
             }
@@ -10114,10 +10066,10 @@
     }
 
     // Utility method used to move dex files during install.
-    private int moveDexFilesLI(PackageParser.Package newPackage) {
+    private int moveDexFilesLI(String oldCodePath, PackageParser.Package newPackage) {
         if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
-            int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
+            int retCode = mInstaller.movedex(oldCodePath, newPackage.codePath,
                                              instructionSet);
             if (retCode != 0) {
                 /*
@@ -10129,8 +10081,8 @@
                  * file from a previous version of the package.
                  */
                 newPackage.mDexOptNeeded = true;
-                mInstaller.rmdex(newPackage.mScanPath, instructionSet);
-                mInstaller.rmdex(newPackage.mPath, instructionSet);
+                mInstaller.rmdex(oldCodePath, instructionSet);
+                mInstaller.rmdex(newPackage.codePath, instructionSet);
             }
         }
         return PackageManager.INSTALL_SUCCEEDED;
@@ -10148,13 +10100,7 @@
             mSettings.writeLPr();
         }
 
-        if ((res.returnCode = moveDexFilesLI(newPackage))
-                != PackageManager.INSTALL_SUCCEEDED) {
-            // Discontinue if moving dex files failed.
-            return;
-        }
-
-        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath);
+        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
 
         synchronized (mPackages) {
             updatePermissionsLPw(newPackage.packageName, newPackage,
@@ -10221,12 +10167,16 @@
                 | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
         PackageParser pp = new PackageParser(tmpPackageFile.getPath());
         pp.setSeparateProcesses(mSeparateProcesses);
-        final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
-                null, mMetrics, parseFlags);
-        if (pkg == null) {
-            res.returnCode = pp.getParseError();
+
+        final PackageParser.Package pkg;
+        try {
+            pkg = pp.parseMonolithicPackage(tmpPackageFile, mMetrics,
+                parseFlags);
+        } catch (PackageParserException e) {
+            res.returnCode = e.error;
             return;
         }
+
         String pkgName = res.name = pkg.packageName;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
             if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
@@ -10234,8 +10184,11 @@
                 return;
             }
         }
-        if (!pp.collectCertificates(pkg, parseFlags)) {
-            res.returnCode = pp.getParseError();
+
+        try {
+            pp.collectCertificates(pkg, parseFlags);
+        } catch (PackageParserException e) {
+            res.returnCode = e.error;
             return;
         }
 
@@ -10265,7 +10218,7 @@
         synchronized (mPackages) {
             // Check whether the newly-scanned package wants to define an already-defined perm
             int N = pkg.permissions.size();
-            for (int i = 0; i < N; i++) {
+            for (int i = N-1; i >= 0; i--) {
                 PackageParser.Permission perm = pkg.permissions.get(i);
                 BasePermission bp = mSettings.mPermissions.get(perm.info.name);
                 if (bp != null) {
@@ -10273,13 +10226,23 @@
                     // also includes the "updating the same package" case, of course.
                     if (compareSignatures(bp.packageSetting.signatures.mSignatures,
                             pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
-                        Slog.w(TAG, "Package " + pkg.packageName
-                                + " attempting to redeclare permission " + perm.info.name
-                                + " already owned by " + bp.sourcePackage);
-                        res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
-                        res.origPermission = perm.info.name;
-                        res.origPackage = bp.sourcePackage;
-                        return;
+                        // If the owning package is the system itself, we log but allow
+                        // install to proceed; we fail the install on all other permission
+                        // redefinitions.
+                        if (!bp.sourcePackage.equals("android")) {
+                            Slog.w(TAG, "Package " + pkg.packageName
+                                    + " attempting to redeclare permission " + perm.info.name
+                                    + " already owned by " + bp.sourcePackage);
+                            res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
+                            res.origPermission = perm.info.name;
+                            res.origPackage = bp.sourcePackage;
+                            return;
+                        } else {
+                            Slog.w(TAG, "Package " + pkg.packageName
+                                    + " attempting to redeclare system permission "
+                                    + perm.info.name + "; ignoring new declaration");
+                            pkg.permissions.remove(i);
+                        }
                     }
                 }
             }
@@ -10330,7 +10293,9 @@
             return;
         }
         // Set application objects path explicitly after the rename
-        setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+        pkg.codePath = args.getCodePath();
+        pkg.applicationInfo.sourceDir = args.getCodePath();
+        pkg.applicationInfo.publicSourceDir = args.getResourcePath();
         pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
         if (replace) {
             replacePackageLI(pkg, parseFlags, scanMode, args.user,
@@ -11210,7 +11175,7 @@
                 publicSrcDir = applicationInfo.publicSourceDir;
             }
         }
-        int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, libDirPath,
+        int res = mInstaller.getSizeInfo(packageName, userHandle, p.codePath, libDirPath,
                 publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps),
                 pStats);
         if (res < 0) {
@@ -12843,7 +12808,7 @@
                                             + " Aborting move and returning error");
                                     returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
                                 } else {
-                                    final String oldCodePath = pkg.mPath;
+                                    final String oldCodePath = pkg.codePath;
                                     final String newCodePath = mp.targetArgs.getCodePath();
                                     final String newResPath = mp.targetArgs.getResourcePath();
                                     final String newNativePath = mp.targetArgs
@@ -12873,18 +12838,17 @@
                                     }
 
                                     if (returnCode == PackageManager.MOVE_SUCCEEDED) {
-                                        pkg.mPath = newCodePath;
+                                        pkg.codePath = newCodePath;
                                         // Move dex files around
-                                        if (moveDexFilesLI(pkg) != PackageManager.INSTALL_SUCCEEDED) {
+                                        if (moveDexFilesLI(oldCodePath, pkg) != PackageManager.INSTALL_SUCCEEDED) {
                                             // Moving of dex files failed. Set
                                             // error code and abort move.
-                                            pkg.mPath = pkg.mScanPath;
+                                            pkg.codePath = oldCodePath;
                                             returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
                                         }
                                     }
 
                                     if (returnCode == PackageManager.MOVE_SUCCEEDED) {
-                                        pkg.mScanPath = newCodePath;
                                         pkg.applicationInfo.sourceDir = newCodePath;
                                         pkg.applicationInfo.publicSourceDir = newResPath;
                                         pkg.applicationInfo.nativeLibraryDir = newNativePath;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b7bc2e1..b941657 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -161,7 +161,6 @@
     private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
 
     private int[] mUserIds;
-    private boolean mGuestEnabled;
     private int mNextSerialNumber;
     private int mUserVersion = 0;
 
@@ -427,43 +426,6 @@
         }
     }
 
-    @Override
-    public void setGuestEnabled(boolean enable) {
-        checkManageUsersPermission("enable guest users");
-        synchronized (mPackagesLock) {
-            if (mGuestEnabled != enable) {
-                mGuestEnabled = enable;
-                // Erase any guest user that currently exists
-                for (int i = 0; i < mUsers.size(); i++) {
-                    UserInfo user = mUsers.valueAt(i);
-                    if (!user.partial && user.isGuest()) {
-                        if (!enable) {
-                            removeUser(user.id);
-                        }
-                        return;
-                    }
-                }
-                // No guest was found
-                if (enable) {
-                    createUser("Guest", UserInfo.FLAG_GUEST);
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean isGuestEnabled() {
-        synchronized (mPackagesLock) {
-            return mGuestEnabled;
-        }
-    }
-
-    @Override
-    public void wipeUser(int userHandle) {
-        checkManageUsersPermission("wipe user");
-        // TODO:
-    }
-
     public void makeInitialized(int userId) {
         checkManageUsersPermission("makeInitialized");
         synchronized (mPackagesLock) {
@@ -583,7 +545,6 @@
     }
 
     private void readUserListLocked() {
-        mGuestEnabled = false;
         if (!mUserListFile.exists()) {
             fallbackToSingleUserLocked();
             return;
@@ -625,9 +586,6 @@
 
                     if (user != null) {
                         mUsers.put(user.id, user);
-                        if (user.isGuest()) {
-                            mGuestEnabled = true;
-                        }
                         if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
                             mNextSerialNumber = user.id + 1;
                         }
@@ -1146,7 +1104,7 @@
             final UserInfo user;
             synchronized (mPackagesLock) {
                 user = mUsers.get(userHandle);
-                if (userHandle == 0 || user == null) {
+                if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
                     return false;
                 }
                 mRemovingUserIds.put(userHandle, true);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d8671d9..fb4b8f0 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -409,6 +409,9 @@
     // Current state of the low power mode setting.
     private boolean mLowPowerModeSetting;
 
+    // Current state of whether the settings are allowing auto low power mode.
+    private boolean mAutoLowPowerModeEnabled;
+
     // True if the battery level is currently considered low.
     private boolean mBatteryLevelLow;
 
@@ -558,6 +561,9 @@
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.LOW_POWER_MODE),
                     false, mSettingsObserver, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+                    false, mSettingsObserver, UserHandle.USER_ALL);
             // Go.
             readConfigurationLocked();
             updateSettingsLocked();
@@ -645,8 +651,12 @@
 
         final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE, 0) != 0;
-        if (lowPowerModeEnabled != mLowPowerModeSetting) {
+        final boolean autoLowPowerModeEnabled = Settings.Global.getInt(resolver,
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15) != 0;
+        if (lowPowerModeEnabled != mLowPowerModeSetting
+                || autoLowPowerModeEnabled != mAutoLowPowerModeEnabled) {
             mLowPowerModeSetting = lowPowerModeEnabled;
+            mAutoLowPowerModeEnabled = autoLowPowerModeEnabled;
             updateLowPowerModeLocked();
         }
 
@@ -654,7 +664,8 @@
     }
 
     void updateLowPowerModeLocked() {
-        final boolean lowPowerModeEnabled = mLowPowerModeSetting || mBatteryLevelLow;
+        final boolean lowPowerModeEnabled = !mIsPowered
+                && (mLowPowerModeSetting || (mAutoLowPowerModeEnabled && mBatteryLevelLow));
         if (mLowPowerModeEnabled != lowPowerModeEnabled) {
             mLowPowerModeEnabled = lowPowerModeEnabled;
             powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
@@ -1197,7 +1208,7 @@
                 }
             }
 
-            if (oldLevelLow != mBatteryLevelLow) {
+            if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
                 updateLowPowerModeLocked();
             }
         }
@@ -2168,6 +2179,8 @@
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
             pw.println("  mSandmanScheduled=" + mSandmanScheduled);
             pw.println("  mSandmanSummoned=" + mSandmanSummoned);
+            pw.println("  mLowPowerModeEnabled=" + mLowPowerModeEnabled);
+            pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
             pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
             pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
@@ -2204,6 +2217,8 @@
             pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
             pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
             pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
+            pw.println("  mLowPowerModeSetting=" + mLowPowerModeSetting);
+            pw.println("  mAutoLowPowerModeEnabled=" + mAutoLowPowerModeEnabled);
             pw.println("  mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
             pw.println("  mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
             pw.println("  mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
deleted file mode 100644
index ab5cc7c..0000000
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task;
-
-import com.android.server.task.controllers.TaskStatus;
-
-/**
- * Interface through which a {@link com.android.server.task.controllers.StateController} informs
- * the {@link com.android.server.task.TaskManagerService} that there are some tasks potentially
- * ready to be run.
- */
-public interface StateChangedListener {
-    /**
-     * Called by the controller to notify the TaskManager that it should check on the state of a
-     * task.
-     */
-    public void onControllerStateChanged();
-
-    /**
-     * Called by the controller to notify the TaskManager that regardless of the state of the task,
-     * it must be run immediately.
-     * @param taskStatus The state of the task which is to be run immediately.
-     */
-    public void onRunTaskNow(TaskStatus taskStatus);
-}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
deleted file mode 100644
index 0c55a1d..0000000
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import android.app.task.ITaskManager;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.content.BroadcastReceiver;
-import android.app.task.TaskService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.server.task.controllers.BatteryController;
-import com.android.server.task.controllers.ConnectivityController;
-import com.android.server.task.controllers.IdleController;
-import com.android.server.task.controllers.StateController;
-import com.android.server.task.controllers.TaskStatus;
-import com.android.server.task.controllers.TimeController;
-
-import java.util.LinkedList;
-
-/**
- * Responsible for taking tasks representing work to be performed by a client app, and determining
- * based on the criteria specified when that task should be run against the client application's
- * endpoint.
- * Implements logic for scheduling, and rescheduling tasks. The TaskManagerService knows nothing
- * about constraints, or the state of active tasks. It receives callbacks from the various
- * controllers and completed tasks and operates accordingly.
- *
- * Note on locking: Any operations that manipulate {@link #mTasks} need to lock on that object.
- * Any function with the suffix 'Locked' also needs to lock on {@link #mTasks}.
- * @hide
- */
-public class TaskManagerService extends com.android.server.SystemService
-        implements StateChangedListener, TaskCompletedListener, TaskMapReadFinishedListener {
-    // TODO: Switch this off for final version.
-    static final boolean DEBUG = true;
-    /** The number of concurrent tasks we run at one time. */
-    private static final int MAX_TASK_CONTEXTS_COUNT = 3;
-    static final String TAG = "TaskManager";
-    /** Master list of tasks. */
-    private final TaskStore mTasks;
-
-    static final int MSG_TASK_EXPIRED = 0;
-    static final int MSG_CHECK_TASKS = 1;
-
-    // Policy constants
-    /**
-     * Minimum # of idle tasks that must be ready in order to force the TM to schedule things
-     * early.
-     */
-    private static final int MIN_IDLE_COUNT = 1;
-    /**
-     * Minimum # of connectivity tasks that must be ready in order to force the TM to schedule
-     * things early.
-     */
-    private static final int MIN_CONNECTIVITY_COUNT = 2;
-    /**
-     * Minimum # of tasks (with no particular constraints) for which the TM will be happy running
-     * some work early.
-     */
-    private static final int MIN_READY_TASKS_COUNT = 4;
-
-    /**
-     * Track Services that have currently active or pending tasks. The index is provided by
-     * {@link TaskStatus#getServiceToken()}
-     */
-    private final List<TaskServiceContext> mActiveServices = new LinkedList<TaskServiceContext>();
-    /** List of controllers that will notify this service of updates to tasks. */
-    private List<StateController> mControllers;
-    /**
-     * Queue of pending tasks. The TaskServiceContext class will receive tasks from this list
-     * when ready to execute them.
-     */
-    private final LinkedList<TaskStatus> mPendingTasks = new LinkedList<TaskStatus>();
-
-    private final TaskHandler mHandler;
-    private final TaskManagerStub mTaskManagerStub;
-    /**
-     * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
-     * still clean up. On reinstall the package will have a new uid.
-     */
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Slog.d(TAG, "Receieved: " + intent.getAction());
-            if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-                int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
-                if (DEBUG) {
-                    Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
-                }
-                cancelTasksForUid(uidRemoved);
-            } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
-                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-                if (DEBUG) {
-                    Slog.d(TAG, "Removing jobs for user: " + userId);
-                }
-                cancelTasksForUser(userId);
-            }
-        }
-    };
-
-    /**
-     * Entry point from client to schedule the provided task.
-     * This cancels the task if it's already been scheduled, and replaces it with the one provided.
-     * @param task Task object containing execution parameters
-     * @param uId The package identifier of the application this task is for.
-     * @param canPersistTask Whether or not the client has the appropriate permissions for
-     *                       persisting this task.
-     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
-     */
-    public int schedule(Task task, int uId, boolean canPersistTask) {
-        TaskStatus taskStatus = new TaskStatus(task, uId, canPersistTask);
-        cancelTask(uId, task.getId());
-        startTrackingTask(taskStatus);
-        return TaskManager.RESULT_SUCCESS;
-    }
-
-    public List<Task> getPendingTasks(int uid) {
-        ArrayList<Task> outList = new ArrayList<Task>();
-        synchronized (mTasks) {
-            for (TaskStatus ts : mTasks.getTasks()) {
-                if (ts.getUid() == uid) {
-                    outList.add(ts.getTask());
-                }
-            }
-        }
-        return outList;
-    }
-
-    private void cancelTasksForUser(int userHandle) {
-        synchronized (mTasks) {
-            List<TaskStatus> tasksForUser = mTasks.getTasksByUser(userHandle);
-            for (TaskStatus toRemove : tasksForUser) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Cancelling: " + toRemove);
-                }
-                cancelTaskLocked(toRemove);
-            }
-        }
-    }
-
-    /**
-     * Entry point from client to cancel all tasks originating from their uid.
-     * This will remove the task from the master list, and cancel the task if it was staged for
-     * execution or being executed.
-     * @param uid To check against for removal of a task.
-     */
-    public void cancelTasksForUid(int uid) {
-        // Remove from master list.
-        synchronized (mTasks) {
-            List<TaskStatus> tasksForUid = mTasks.getTasksByUid(uid);
-            for (TaskStatus toRemove : tasksForUid) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Cancelling: " + toRemove);
-                }
-                cancelTaskLocked(toRemove);
-            }
-        }
-    }
-
-    /**
-     * Entry point from client to cancel the task corresponding to the taskId provided.
-     * This will remove the task from the master list, and cancel the task if it was staged for
-     * execution or being executed.
-     * @param uid Uid of the calling client.
-     * @param taskId Id of the task, provided at schedule-time.
-     */
-    public void cancelTask(int uid, int taskId) {
-        TaskStatus toCancel;
-        synchronized (mTasks) {
-            toCancel = mTasks.getTaskByUidAndTaskId(uid, taskId);
-            if (toCancel != null) {
-                cancelTaskLocked(toCancel);
-            }
-        }
-    }
-
-    private void cancelTaskLocked(TaskStatus cancelled) {
-        // Remove from store.
-        stopTrackingTask(cancelled);
-        // Remove from pending queue.
-        mPendingTasks.remove(cancelled);
-        // Cancel if running.
-        stopTaskOnServiceContextLocked(cancelled);
-    }
-
-    /**
-     * Initializes the system service.
-     * <p>
-     * Subclasses must define a single argument constructor that accepts the context
-     * and passes it to super.
-     * </p>
-     *
-     * @param context The system server context.
-     */
-    public TaskManagerService(Context context) {
-        super(context);
-        // Create the controllers.
-        mControllers = new LinkedList<StateController>();
-        mControllers.add(ConnectivityController.get(this));
-        mControllers.add(TimeController.get(this));
-        mControllers.add(IdleController.get(this));
-        mControllers.add(BatteryController.get(this));
-
-        mHandler = new TaskHandler(context.getMainLooper());
-        mTaskManagerStub = new TaskManagerStub();
-        // Create the "runners".
-        for (int i = 0; i < MAX_TASK_CONTEXTS_COUNT; i++) {
-            mActiveServices.add(
-                    new TaskServiceContext(this, context.getMainLooper()));
-        }
-        mTasks = TaskStore.initAndGet(this);
-    }
-
-    @Override
-    public void onStart() {
-        publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
-    }
-
-    @Override
-    public void onBootPhase(int phase) {
-        if (PHASE_SYSTEM_SERVICES_READY == phase) {
-            // Register br for package removals and user removals.
-            final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
-            filter.addDataScheme("package");
-            getContext().registerReceiverAsUser(
-                    mBroadcastReceiver, UserHandle.ALL, filter, null, null);
-            final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
-            getContext().registerReceiverAsUser(
-                    mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
-        }
-    }
-
-    /**
-     * Called when we have a task status object that we need to insert in our
-     * {@link com.android.server.task.TaskStore}, and make sure all the relevant controllers know
-     * about.
-     */
-    private void startTrackingTask(TaskStatus taskStatus) {
-        boolean update;
-        synchronized (mTasks) {
-            update = mTasks.add(taskStatus);
-        }
-        for (StateController controller : mControllers) {
-            if (update) {
-                controller.maybeStopTrackingTask(taskStatus);
-            }
-            controller.maybeStartTrackingTask(taskStatus);
-        }
-    }
-
-    /**
-     * Called when we want to remove a TaskStatus object that we've finished executing. Returns the
-     * object removed.
-     */
-    private boolean stopTrackingTask(TaskStatus taskStatus) {
-        boolean removed;
-        synchronized (mTasks) {
-            // Remove from store as well as controllers.
-            removed = mTasks.remove(taskStatus);
-        }
-        if (removed) {
-            for (StateController controller : mControllers) {
-                controller.maybeStopTrackingTask(taskStatus);
-            }
-        }
-        return removed;
-    }
-
-    private boolean stopTaskOnServiceContextLocked(TaskStatus ts) {
-        for (TaskServiceContext tsc : mActiveServices) {
-            final TaskStatus executing = tsc.getRunningTask();
-            if (executing != null && executing.matches(ts.getUid(), ts.getTaskId())) {
-                tsc.cancelExecutingTask();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * @param ts TaskStatus we are querying against.
-     * @return Whether or not the task represented by the status object is currently being run or
-     * is pending.
-     */
-    private boolean isCurrentlyActiveLocked(TaskStatus ts) {
-        for (TaskServiceContext serviceContext : mActiveServices) {
-            final TaskStatus running = serviceContext.getRunningTask();
-            if (running != null && running.matches(ts.getUid(), ts.getTaskId())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * A task is rescheduled with exponential back-off if the client requests this from their
-     * execution logic.
-     * A caveat is for idle-mode tasks, for which the idle-mode constraint will usurp the
-     * timeliness of the reschedule. For an idle-mode task, no deadline is given.
-     * @param failureToReschedule Provided task status that we will reschedule.
-     * @return A newly instantiated TaskStatus with the same constraints as the last task except
-     * with adjusted timing constraints.
-     */
-    private TaskStatus getRescheduleTaskForFailure(TaskStatus failureToReschedule) {
-        final long elapsedNowMillis = SystemClock.elapsedRealtime();
-        final Task task = failureToReschedule.getTask();
-
-        final long initialBackoffMillis = task.getInitialBackoffMillis();
-        final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
-        long newEarliestRuntimeElapsed = elapsedNowMillis;
-
-        switch (task.getBackoffPolicy()) {
-            case Task.BackoffPolicy.LINEAR:
-                newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
-                break;
-            default:
-                if (DEBUG) {
-                    Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
-                }
-            case Task.BackoffPolicy.EXPONENTIAL:
-                newEarliestRuntimeElapsed +=
-                        Math.pow(initialBackoffMillis * 0.001, backoffAttempt) * 1000;
-                break;
-        }
-        newEarliestRuntimeElapsed =
-                Math.min(newEarliestRuntimeElapsed, Task.MAX_BACKOFF_DELAY_MILLIS);
-        return new TaskStatus(failureToReschedule, newEarliestRuntimeElapsed,
-                TaskStatus.NO_LATEST_RUNTIME, backoffAttempt);
-    }
-
-    /**
-     * Called after a periodic has executed so we can to re-add it. We take the last execution time
-     * of the task to be the time of completion (i.e. the time at which this function is called).
-     * This could be inaccurate b/c the task can run for as long as
-     * {@link com.android.server.task.TaskServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
-     * to underscheduling at least, rather than if we had taken the last execution time to be the
-     * start of the execution.
-     * @return A new task representing the execution criteria for this instantiation of the
-     * recurring task.
-     */
-    private TaskStatus getRescheduleTaskForPeriodic(TaskStatus periodicToReschedule) {
-        final long elapsedNow = SystemClock.elapsedRealtime();
-        // Compute how much of the period is remaining.
-        long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
-        long newEarliestRunTimeElapsed = elapsedNow + runEarly;
-        long period = periodicToReschedule.getTask().getIntervalMillis();
-        long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
-
-        if (DEBUG) {
-            Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
-                    newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
-        }
-        return new TaskStatus(periodicToReschedule, newEarliestRunTimeElapsed,
-                newLatestRuntimeElapsed, 0 /* backoffAttempt */);
-    }
-
-    // TaskCompletedListener implementations.
-
-    /**
-     * A task just finished executing. We fetch the
-     * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
-     * whether we want to reschedule we readd it to the controllers.
-     * @param taskStatus Completed task.
-     * @param needsReschedule Whether the implementing class should reschedule this task.
-     */
-    @Override
-    public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule) {
-        if (DEBUG) {
-            Slog.d(TAG, "Completed " + taskStatus + ", reschedule=" + needsReschedule);
-        }
-        if (!stopTrackingTask(taskStatus)) {
-            if (DEBUG) {
-                Slog.e(TAG, "Error removing task: could not find task to remove. Was task " +
-                        "removed while executing?");
-            }
-            return;
-        }
-        if (needsReschedule) {
-            TaskStatus rescheduled = getRescheduleTaskForFailure(taskStatus);
-            startTrackingTask(rescheduled);
-        } else if (taskStatus.getTask().isPeriodic()) {
-            TaskStatus rescheduledPeriodic = getRescheduleTaskForPeriodic(taskStatus);
-            startTrackingTask(rescheduledPeriodic);
-        }
-        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
-    }
-
-    // StateChangedListener implementations.
-
-    /**
-     * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
-     * made on the main thread.
-     * For now this takes the task and if it's ready to run it will run it. In future we might not
-     * provide the task, so that the StateChangedListener has to run through its list of tasks to
-     * see which are ready. This will further decouple the controllers from the execution logic.
-     */
-    @Override
-    public void onControllerStateChanged() {
-        // Post a message to to run through the list of tasks and start/stop any that are eligible.
-        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
-    }
-
-    @Override
-    public void onRunTaskNow(TaskStatus taskStatus) {
-        mHandler.obtainMessage(MSG_TASK_EXPIRED, taskStatus).sendToTarget();
-    }
-
-    /**
-     * Disk I/O is finished, take the list of tasks we read from disk and add them to our
-     * {@link TaskStore}.
-     * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
-     * and is called once at boot.
-     */
-    @Override
-    public void onTaskMapReadFinished(List<TaskStatus> tasks) {
-        synchronized (mTasks) {
-            for (TaskStatus ts : tasks) {
-                if (mTasks.containsTaskIdForUid(ts.getTaskId(), ts.getUid())) {
-                    // An app with BOOT_COMPLETED *might* have decided to reschedule their task, in
-                    // the same amount of time it took us to read it from disk. If this is the case
-                    // we leave it be.
-                    continue;
-                }
-                startTrackingTask(ts);
-            }
-        }
-    }
-
-    private class TaskHandler extends Handler {
-
-        public TaskHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message message) {
-            switch (message.what) {
-                case MSG_TASK_EXPIRED:
-                    synchronized (mTasks) {
-                        TaskStatus runNow = (TaskStatus) message.obj;
-                        if (!mPendingTasks.contains(runNow)) {
-                            mPendingTasks.add(runNow);
-                        }
-                    }
-                    queueReadyTasksForExecutionH();
-                    break;
-                case MSG_CHECK_TASKS:
-                    // Check the list of tasks and run some of them if we feel inclined.
-                    maybeQueueReadyTasksForExecutionH();
-                    break;
-            }
-            maybeRunPendingTasksH();
-            // Don't remove TASK_EXPIRED in case one came along while processing the queue.
-            removeMessages(MSG_CHECK_TASKS);
-        }
-
-        /**
-         * Run through list of tasks and execute all possible - at least one is expired so we do
-         * as many as we can.
-         */
-        private void queueReadyTasksForExecutionH() {
-            synchronized (mTasks) {
-                for (TaskStatus ts : mTasks.getTasks()) {
-                    if (isReadyToBeExecutedLocked(ts)) {
-                        mPendingTasks.add(ts);
-                    } else if (isReadyToBeCancelledLocked(ts)) {
-                        stopTaskOnServiceContextLocked(ts);
-                    }
-                }
-            }
-        }
-
-        /**
-         * The state of at least one task has changed. Here is where we could enforce various
-         * policies on when we want to execute tasks.
-         * Right now the policy is such:
-         * If >1 of the ready tasks is idle mode we send all of them off
-         * if more than 2 network connectivity tasks are ready we send them all off.
-         * If more than 4 tasks total are ready we send them all off.
-         * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
-         */
-        private void maybeQueueReadyTasksForExecutionH() {
-            synchronized (mTasks) {
-                int idleCount = 0;
-                int backoffCount = 0;
-                int connectivityCount = 0;
-                List<TaskStatus> runnableTasks = new ArrayList<TaskStatus>();
-                for (TaskStatus ts : mTasks.getTasks()) {
-                    if (isReadyToBeExecutedLocked(ts)) {
-                        if (ts.getNumFailures() > 0) {
-                            backoffCount++;
-                        }
-                        if (ts.hasIdleConstraint()) {
-                            idleCount++;
-                        }
-                        if (ts.hasConnectivityConstraint() || ts.hasUnmeteredConstraint()) {
-                            connectivityCount++;
-                        }
-                        runnableTasks.add(ts);
-                    } else if (isReadyToBeCancelledLocked(ts)) {
-                        stopTaskOnServiceContextLocked(ts);
-                    }
-                }
-                if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
-                        connectivityCount >= MIN_CONNECTIVITY_COUNT ||
-                        runnableTasks.size() >= MIN_READY_TASKS_COUNT) {
-                    for (TaskStatus ts : runnableTasks) {
-                        mPendingTasks.add(ts);
-                    }
-                }
-            }
-        }
-
-        /**
-         * Criteria for moving a job into the pending queue:
-         *      - It's ready.
-         *      - It's not pending.
-         *      - It's not already running on a TSC.
-         */
-        private boolean isReadyToBeExecutedLocked(TaskStatus ts) {
-              return ts.isReady() && !mPendingTasks.contains(ts) && !isCurrentlyActiveLocked(ts);
-        }
-
-        /**
-         * Criteria for cancelling an active job:
-         *      - It's not ready
-         *      - It's running on a TSC.
-         */
-        private boolean isReadyToBeCancelledLocked(TaskStatus ts) {
-            return !ts.isReady() && isCurrentlyActiveLocked(ts);
-        }
-
-        /**
-         * Reconcile jobs in the pending queue against available execution contexts.
-         * A controller can force a task into the pending queue even if it's already running, but
-         * here is where we decide whether to actually execute it.
-         */
-        private void maybeRunPendingTasksH() {
-            synchronized (mTasks) {
-                Iterator<TaskStatus> it = mPendingTasks.iterator();
-                while (it.hasNext()) {
-                    TaskStatus nextPending = it.next();
-                    TaskServiceContext availableContext = null;
-                    for (TaskServiceContext tsc : mActiveServices) {
-                        final TaskStatus running = tsc.getRunningTask();
-                        if (running != null && running.matches(nextPending.getUid(),
-                                nextPending.getTaskId())) {
-                            // Already running this tId for this uId, skip.
-                            availableContext = null;
-                            break;
-                        }
-                        if (tsc.isAvailable()) {
-                            availableContext = tsc;
-                        }
-                    }
-                    if (availableContext != null) {
-                        if (!availableContext.executeRunnableTask(nextPending)) {
-                            if (DEBUG) {
-                                Slog.d(TAG, "Error executing " + nextPending);
-                            }
-                            mTasks.remove(nextPending);
-                        }
-                        it.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Binder stub trampoline implementation
-     */
-    final class TaskManagerStub extends ITaskManager.Stub {
-        /** Cache determination of whether a given app can persist tasks
-         * key is uid of the calling app; value is undetermined/true/false
-         */
-        private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
-
-        // Enforce that only the app itself (or shared uid participant) can schedule a
-        // task that runs one of the app's services, as well as verifying that the
-        // named service properly requires the BIND_TASK_SERVICE permission
-        private void enforceValidJobRequest(int uid, Task job) {
-            final PackageManager pm = getContext().getPackageManager();
-            final ComponentName service = job.getService();
-            try {
-                ServiceInfo si = pm.getServiceInfo(service, 0);
-                if (si.applicationInfo.uid != uid) {
-                    throw new IllegalArgumentException("uid " + uid +
-                            " cannot schedule job in " + service.getPackageName());
-                }
-                if (!TaskService.PERMISSION_BIND.equals(si.permission)) {
-                    throw new IllegalArgumentException("Scheduled service " + service
-                            + " does not require android.permission.BIND_TASK_SERVICE permission");
-                }
-            } catch (NameNotFoundException e) {
-                throw new IllegalArgumentException("No such service: " + service);
-            }
-        }
-
-        private boolean canPersistJobs(int pid, int uid) {
-            // If we get this far we're good to go; all we need to do now is check
-            // whether the app is allowed to persist its scheduled work.
-            final boolean canPersist;
-            synchronized (mPersistCache) {
-                Boolean cached = mPersistCache.get(uid);
-                if (cached != null) {
-                    canPersist = cached.booleanValue();
-                } else {
-                    // Persisting tasks is tantamount to running at boot, so we permit
-                    // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
-                    // permission
-                    int result = getContext().checkPermission(
-                            android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
-                    canPersist = (result == PackageManager.PERMISSION_GRANTED);
-                    mPersistCache.put(uid, canPersist);
-                }
-            }
-            return canPersist;
-        }
-
-        // ITaskManager implementation
-        @Override
-        public int schedule(Task task) throws RemoteException {
-            if (DEBUG) {
-                Slog.d(TAG, "Scheduling task: " + task);
-            }
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-
-            enforceValidJobRequest(uid, task);
-            final boolean canPersist = canPersistJobs(pid, uid);
-
-            long ident = Binder.clearCallingIdentity();
-            try {
-                return TaskManagerService.this.schedule(task, uid, canPersist);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        @Override
-        public List<Task> getAllPendingTasks() throws RemoteException {
-            final int uid = Binder.getCallingUid();
-
-            long ident = Binder.clearCallingIdentity();
-            try {
-                return TaskManagerService.this.getPendingTasks(uid);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        @Override
-        public void cancelAll() throws RemoteException {
-            final int uid = Binder.getCallingUid();
-
-            long ident = Binder.clearCallingIdentity();
-            try {
-                TaskManagerService.this.cancelTasksForUid(uid);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        @Override
-        public void cancel(int taskId) throws RemoteException {
-            final int uid = Binder.getCallingUid();
-
-            long ident = Binder.clearCallingIdentity();
-            try {
-                TaskManagerService.this.cancelTask(uid, taskId);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        /**
-         * "dumpsys" infrastructure
-         */
-        @Override
-        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-            long identityToken = Binder.clearCallingIdentity();
-            try {
-                TaskManagerService.this.dumpInternal(pw);
-            } finally {
-                Binder.restoreCallingIdentity(identityToken);
-            }
-        }
-    };
-
-    void dumpInternal(PrintWriter pw) {
-        synchronized (mTasks) {
-            pw.println("Registered tasks:");
-            if (mTasks.size() > 0) {
-                for (TaskStatus ts : mTasks.getTasks()) {
-                    ts.dump(pw, "  ");
-                }
-            } else {
-                pw.println();
-                pw.println("No tasks scheduled.");
-            }
-            for (StateController controller : mControllers) {
-                pw.println();
-                controller.dumpControllerState(pw);
-            }
-            pw.println();
-            pw.println("Pending");
-            for (TaskStatus taskStatus : mPendingTasks) {
-                pw.println(taskStatus.hashCode());
-            }
-            pw.println();
-            pw.println("Active jobs:");
-            for (TaskServiceContext tsc : mActiveServices) {
-                if (tsc.isAvailable()) {
-                    continue;
-                } else {
-                    pw.println(tsc.getRunningTask().hashCode() + " for: " +
-                            (SystemClock.elapsedRealtime()
-                                    - tsc.getExecutionStartTimeElapsed())/1000 + "s " +
-                            "timeout: " + tsc.getTimeoutElapsed());
-                }
-            }
-        }
-        pw.println();
-    }
-}
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
deleted file mode 100644
index 9e095e7..0000000
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task;
-
-import android.content.ComponentName;
-import android.app.task.Task;
-import android.content.Context;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.AtomicFile;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.Xml;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.server.IoThread;
-import com.android.server.task.controllers.TaskStatus;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-/**
- * Maintain a list of classes, and accessor methods/logic for these tasks.
- * This class offers the following functionality:
- *     - When a task is added, it will determine if the task requirements have changed (update) and
- *       whether the controllers need to be updated.
- *     - Persists Tasks, figures out when to to rewrite the Task to disk.
- *     - Handles rescheduling of tasks.
- *       - When a periodic task is executed and must be re-added.
- *       - When a task fails and the client requests that it be retried with backoff.
- *       - This class <strong>is not</strong> thread-safe.
- *
- * Note on locking:
- *      All callers to this class must <strong>lock on the class object they are calling</strong>.
- *      This is important b/c {@link com.android.server.task.TaskStore.WriteTasksMapToDiskRunnable}
- *      and {@link com.android.server.task.TaskStore.ReadTaskMapFromDiskRunnable} lock on that
- *      object.
- */
-public class TaskStore {
-    private static final String TAG = "TaskManagerStore";
-    private static final boolean DEBUG = TaskManagerService.DEBUG;
-
-    /** Threshold to adjust how often we want to write to the db. */
-    private static final int MAX_OPS_BEFORE_WRITE = 1;
-    final ArraySet<TaskStatus> mTasksSet;
-    final Context mContext;
-
-    private int mDirtyOperations;
-
-    private static final Object sSingletonLock = new Object();
-    private final AtomicFile mTasksFile;
-    /** Handler backed by IoThread for writing to disk. */
-    private final Handler mIoHandler = IoThread.getHandler();
-    private static TaskStore sSingleton;
-
-    /** Used by the {@Link TaskManagerService} to instantiate the TaskStore. */
-    static TaskStore initAndGet(TaskManagerService taskManagerService) {
-        synchronized (sSingletonLock) {
-            if (sSingleton == null) {
-                sSingleton = new TaskStore(taskManagerService.getContext(),
-                        Environment.getDataDirectory(), taskManagerService);
-            }
-            return sSingleton;
-        }
-    }
-
-    @VisibleForTesting
-    public static TaskStore initAndGetForTesting(Context context, File dataDir,
-                                                 TaskMapReadFinishedListener callback) {
-        return new TaskStore(context, dataDir, callback);
-    }
-
-    private TaskStore(Context context, File dataDir, TaskMapReadFinishedListener callback) {
-        mContext = context;
-        mDirtyOperations = 0;
-
-        File systemDir = new File(dataDir, "system");
-        File taskDir = new File(systemDir, "task");
-        taskDir.mkdirs();
-        mTasksFile = new AtomicFile(new File(taskDir, "tasks.xml"));
-
-        mTasksSet = new ArraySet<TaskStatus>();
-
-        readTaskMapFromDiskAsync(callback);
-    }
-
-    /**
-     * Add a task to the master list, persisting it if necessary. If the TaskStatus already exists,
-     * it will be replaced.
-     * @param taskStatus Task to add.
-     * @return Whether or not an equivalent TaskStatus was replaced by this operation.
-     */
-    public boolean add(TaskStatus taskStatus) {
-        boolean replaced = mTasksSet.remove(taskStatus);
-        mTasksSet.add(taskStatus);
-        if (taskStatus.isPersisted()) {
-            maybeWriteStatusToDiskAsync();
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "Added task status to store: " + taskStatus);
-        }
-        return replaced;
-    }
-
-    /**
-     * Whether this taskStatus object already exists in the TaskStore.
-     */
-    public boolean containsTaskIdForUid(int taskId, int uId) {
-        for (TaskStatus ts : mTasksSet) {
-            if (ts.getUid() == uId && ts.getTaskId() == taskId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public int size() {
-        return mTasksSet.size();
-    }
-
-    /**
-     * Remove the provided task. Will also delete the task if it was persisted.
-     * @return Whether or not the task existed to be removed.
-     */
-    public boolean remove(TaskStatus taskStatus) {
-        boolean removed = mTasksSet.remove(taskStatus);
-        if (!removed) {
-            if (DEBUG) {
-                Slog.d(TAG, "Couldn't remove task: didn't exist: " + taskStatus);
-            }
-            return false;
-        }
-        maybeWriteStatusToDiskAsync();
-        return removed;
-    }
-
-    @VisibleForTesting
-    public void clear() {
-        mTasksSet.clear();
-        maybeWriteStatusToDiskAsync();
-    }
-
-    public List<TaskStatus> getTasksByUser(int userHandle) {
-        List<TaskStatus> matchingTasks = new ArrayList<TaskStatus>();
-        Iterator<TaskStatus> it = mTasksSet.iterator();
-        while (it.hasNext()) {
-            TaskStatus ts = it.next();
-            if (UserHandle.getUserId(ts.getUid()) == userHandle) {
-                matchingTasks.add(ts);
-            }
-        }
-        return matchingTasks;
-    }
-
-    /**
-     * @param uid Uid of the requesting app.
-     * @return All TaskStatus objects for a given uid from the master list.
-     */
-    public List<TaskStatus> getTasksByUid(int uid) {
-        List<TaskStatus> matchingTasks = new ArrayList<TaskStatus>();
-        Iterator<TaskStatus> it = mTasksSet.iterator();
-        while (it.hasNext()) {
-            TaskStatus ts = it.next();
-            if (ts.getUid() == uid) {
-                matchingTasks.add(ts);
-            }
-        }
-        return matchingTasks;
-    }
-
-    /**
-     * @param uid Uid of the requesting app.
-     * @param taskId Task id, specified at schedule-time.
-     * @return the TaskStatus that matches the provided uId and taskId, or null if none found.
-     */
-    public TaskStatus getTaskByUidAndTaskId(int uid, int taskId) {
-        Iterator<TaskStatus> it = mTasksSet.iterator();
-        while (it.hasNext()) {
-            TaskStatus ts = it.next();
-            if (ts.getUid() == uid && ts.getTaskId() == taskId) {
-                return ts;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * @return The live array of TaskStatus objects.
-     */
-    public ArraySet<TaskStatus> getTasks() {
-        return mTasksSet;
-    }
-
-    /** Version of the db schema. */
-    private static final int TASKS_FILE_VERSION = 0;
-    /** Tag corresponds to constraints this task needs. */
-    private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints";
-    /** Tag corresponds to execution parameters. */
-    private static final String XML_TAG_PERIODIC = "periodic";
-    private static final String XML_TAG_ONEOFF = "one-off";
-    private static final String XML_TAG_EXTRAS = "extras";
-
-    /**
-     * Every time the state changes we write all the tasks in one swathe, instead of trying to
-     * track incremental changes.
-     * @return Whether the operation was successful. This will only fail for e.g. if the system is
-     * low on storage. If this happens, we continue as normal
-     */
-    private void maybeWriteStatusToDiskAsync() {
-        mDirtyOperations++;
-        if (mDirtyOperations >= MAX_OPS_BEFORE_WRITE) {
-            if (DEBUG) {
-                Slog.v(TAG, "Writing tasks to disk.");
-            }
-            mIoHandler.post(new WriteTasksMapToDiskRunnable());
-        }
-    }
-
-    private void readTaskMapFromDiskAsync(TaskMapReadFinishedListener callback) {
-        mIoHandler.post(new ReadTaskMapFromDiskRunnable(callback));
-    }
-
-    public void readTaskMapFromDisk(TaskMapReadFinishedListener callback) {
-        new ReadTaskMapFromDiskRunnable(callback).run();
-    }
-
-    /**
-     * Runnable that writes {@link #mTasksSet} out to xml.
-     * NOTE: This Runnable locks on TaskStore.this
-     */
-    private class WriteTasksMapToDiskRunnable implements Runnable {
-        @Override
-        public void run() {
-            final long startElapsed = SystemClock.elapsedRealtime();
-            synchronized (TaskStore.this) {
-                writeTasksMapImpl();
-            }
-            if (TaskManagerService.DEBUG) {
-                Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
-                        - startElapsed) + "ms");
-            }
-        }
-
-        private void writeTasksMapImpl() {
-            try {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(baos, "utf-8");
-                out.startDocument(null, true);
-                out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
-                out.startTag(null, "task-info");
-                out.attribute(null, "version", Integer.toString(TASKS_FILE_VERSION));
-                for (int i = 0; i < mTasksSet.size(); i++) {
-                    final TaskStatus taskStatus = mTasksSet.valueAt(i);
-                    if (DEBUG) {
-                        Slog.d(TAG, "Saving task " + taskStatus.getTaskId());
-                    }
-                    out.startTag(null, "task");
-                    addIdentifierAttributesToTaskTag(out, taskStatus);
-                    writeConstraintsToXml(out, taskStatus);
-                    writeExecutionCriteriaToXml(out, taskStatus);
-                    writeBundleToXml(taskStatus.getExtras(), out);
-                    out.endTag(null, "task");
-                }
-                out.endTag(null, "task-info");
-                out.endDocument();
-
-                // Write out to disk in one fell sweep.
-                FileOutputStream fos = mTasksFile.startWrite();
-                fos.write(baos.toByteArray());
-                mTasksFile.finishWrite(fos);
-                mDirtyOperations = 0;
-            } catch (IOException e) {
-                if (DEBUG) {
-                    Slog.v(TAG, "Error writing out task data.", e);
-                }
-            } catch (XmlPullParserException e) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Error persisting bundle.", e);
-                }
-            }
-        }
-
-        /** Write out a tag with data comprising the required fields of this task and its client. */
-        private void addIdentifierAttributesToTaskTag(XmlSerializer out, TaskStatus taskStatus)
-                throws IOException {
-            out.attribute(null, "taskid", Integer.toString(taskStatus.getTaskId()));
-            out.attribute(null, "package", taskStatus.getServiceComponent().getPackageName());
-            out.attribute(null, "class", taskStatus.getServiceComponent().getClassName());
-            out.attribute(null, "uid", Integer.toString(taskStatus.getUid()));
-        }
-
-        private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
-                throws IOException, XmlPullParserException {
-            out.startTag(null, XML_TAG_EXTRAS);
-            extras.saveToXml(out);
-            out.endTag(null, XML_TAG_EXTRAS);
-        }
-        /**
-         * Write out a tag with data identifying this tasks constraints. If the constraint isn't here
-         * it doesn't apply.
-         */
-        private void writeConstraintsToXml(XmlSerializer out, TaskStatus taskStatus) throws IOException {
-            out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
-            if (taskStatus.hasUnmeteredConstraint()) {
-                out.attribute(null, "unmetered", Boolean.toString(true));
-            }
-            if (taskStatus.hasConnectivityConstraint()) {
-                out.attribute(null, "connectivity", Boolean.toString(true));
-            }
-            if (taskStatus.hasIdleConstraint()) {
-                out.attribute(null, "idle", Boolean.toString(true));
-            }
-            if (taskStatus.hasChargingConstraint()) {
-                out.attribute(null, "charging", Boolean.toString(true));
-            }
-            out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
-        }
-
-        private void writeExecutionCriteriaToXml(XmlSerializer out, TaskStatus taskStatus)
-                throws IOException {
-            final Task task = taskStatus.getTask();
-            if (taskStatus.getTask().isPeriodic()) {
-                out.startTag(null, XML_TAG_PERIODIC);
-                out.attribute(null, "period", Long.toString(task.getIntervalMillis()));
-            } else {
-                out.startTag(null, XML_TAG_ONEOFF);
-            }
-
-            if (taskStatus.hasDeadlineConstraint()) {
-                // Wall clock deadline.
-                final long deadlineWallclock =  System.currentTimeMillis() +
-                        (taskStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime());
-                out.attribute(null, "deadline", Long.toString(deadlineWallclock));
-            }
-            if (taskStatus.hasTimingDelayConstraint()) {
-                final long delayWallclock = System.currentTimeMillis() +
-                        (taskStatus.getEarliestRunTime() - SystemClock.elapsedRealtime());
-                out.attribute(null, "delay", Long.toString(delayWallclock));
-            }
-
-            // Only write out back-off policy if it differs from the default.
-            // This also helps the case where the task is idle -> these aren't allowed to specify
-            // back-off.
-            if (taskStatus.getTask().getInitialBackoffMillis() != Task.DEFAULT_INITIAL_BACKOFF_MILLIS
-                    || taskStatus.getTask().getBackoffPolicy() != Task.DEFAULT_BACKOFF_POLICY) {
-                out.attribute(null, "backoff-policy", Integer.toString(task.getBackoffPolicy()));
-                out.attribute(null, "initial-backoff", Long.toString(task.getInitialBackoffMillis()));
-            }
-            if (task.isPeriodic()) {
-                out.endTag(null, XML_TAG_PERIODIC);
-            } else {
-                out.endTag(null, XML_TAG_ONEOFF);
-            }
-        }
-    }
-
-    /**
-     * Runnable that reads list of persisted task from xml.
-     * NOTE: This Runnable locks on TaskStore.this
-     */
-    private class ReadTaskMapFromDiskRunnable implements Runnable {
-        private TaskMapReadFinishedListener mCallback;
-        public ReadTaskMapFromDiskRunnable(TaskMapReadFinishedListener callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void run() {
-            try {
-                List<TaskStatus> tasks;
-                FileInputStream fis = mTasksFile.openRead();
-                synchronized (TaskStore.this) {
-                    tasks = readTaskMapImpl(fis);
-                }
-                fis.close();
-                if (tasks != null) {
-                    mCallback.onTaskMapReadFinished(tasks);
-                }
-            } catch (FileNotFoundException e) {
-                if (TaskManagerService.DEBUG) {
-                    Slog.d(TAG, "Could not find tasks file, probably there was nothing to load.");
-                }
-            } catch (XmlPullParserException e) {
-                if (TaskManagerService.DEBUG) {
-                    Slog.d(TAG, "Error parsing xml.", e);
-                }
-            } catch (IOException e) {
-                if (TaskManagerService.DEBUG) {
-                    Slog.d(TAG, "Error parsing xml.", e);
-                }
-            }
-        }
-
-        private List<TaskStatus> readTaskMapImpl(FileInputStream fis) throws XmlPullParserException, IOException {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(fis, null);
-
-            int eventType = parser.getEventType();
-            while (eventType != XmlPullParser.START_TAG &&
-                    eventType != XmlPullParser.END_DOCUMENT) {
-                eventType = parser.next();
-                Slog.d(TAG, parser.getName());
-            }
-            if (eventType == XmlPullParser.END_DOCUMENT) {
-                if (DEBUG) {
-                    Slog.d(TAG, "No persisted tasks.");
-                }
-                return null;
-            }
-
-            String tagName = parser.getName();
-            if ("task-info".equals(tagName)) {
-                final List<TaskStatus> tasks = new ArrayList<TaskStatus>();
-                // Read in version info.
-                try {
-                    int version = Integer.valueOf(parser.getAttributeValue(null, "version"));
-                    if (version != TASKS_FILE_VERSION) {
-                        Slog.d(TAG, "Invalid version number, aborting tasks file read.");
-                        return null;
-                    }
-                } catch (NumberFormatException e) {
-                    Slog.e(TAG, "Invalid version number, aborting tasks file read.");
-                    return null;
-                }
-                eventType = parser.next();
-                do {
-                    // Read each <task/>
-                    if (eventType == XmlPullParser.START_TAG) {
-                        tagName = parser.getName();
-                        // Start reading task.
-                        if ("task".equals(tagName)) {
-                            TaskStatus persistedTask = restoreTaskFromXml(parser);
-                            if (persistedTask != null) {
-                                if (DEBUG) {
-                                    Slog.d(TAG, "Read out " + persistedTask);
-                                }
-                                tasks.add(persistedTask);
-                            } else {
-                                Slog.d(TAG, "Error reading task from file.");
-                            }
-                        }
-                    }
-                    eventType = parser.next();
-                } while (eventType != XmlPullParser.END_DOCUMENT);
-                return tasks;
-            }
-            return null;
-        }
-
-        /**
-         * @param parser Xml parser at the beginning of a "<task/>" tag. The next "parser.next()" call
-         *               will take the parser into the body of the task tag.
-         * @return Newly instantiated task holding all the information we just read out of the xml tag.
-         */
-        private TaskStatus restoreTaskFromXml(XmlPullParser parser) throws XmlPullParserException,
-                IOException {
-            Task.Builder taskBuilder;
-            int uid;
-
-            // Read out task identifier attributes.
-            try {
-                taskBuilder = buildBuilderFromXml(parser);
-                uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
-            } catch (NumberFormatException e) {
-                Slog.e(TAG, "Error parsing task's required fields, skipping");
-                return null;
-            }
-
-            int eventType;
-            // Read out constraints tag.
-            do {
-                eventType = parser.next();
-            } while (eventType == XmlPullParser.TEXT);  // Push through to next START_TAG.
-
-            if (!(eventType == XmlPullParser.START_TAG &&
-                    XML_TAG_PARAMS_CONSTRAINTS.equals(parser.getName()))) {
-                // Expecting a <constraints> start tag.
-                return null;
-            }
-            try {
-                buildConstraintsFromXml(taskBuilder, parser);
-            } catch (NumberFormatException e) {
-                Slog.d(TAG, "Error reading constraints, skipping.");
-                return null;
-            }
-            parser.next(); // Consume </constraints>
-
-            // Read out execution parameters tag.
-            do {
-                eventType = parser.next();
-            } while (eventType == XmlPullParser.TEXT);
-            if (eventType != XmlPullParser.START_TAG) {
-                return null;
-            }
-
-            Pair<Long, Long> runtimes;
-            try {
-                runtimes = buildExecutionTimesFromXml(parser);
-            } catch (NumberFormatException e) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Error parsing execution time parameters, skipping.");
-                }
-                return null;
-            }
-
-            if (XML_TAG_PERIODIC.equals(parser.getName())) {
-                try {
-                    String val = parser.getAttributeValue(null, "period");
-                    taskBuilder.setPeriodic(Long.valueOf(val));
-                } catch (NumberFormatException e) {
-                    Slog.d(TAG, "Error reading periodic execution criteria, skipping.");
-                    return null;
-                }
-            } else if (XML_TAG_ONEOFF.equals(parser.getName())) {
-                try {
-                    if (runtimes.first != TaskStatus.NO_EARLIEST_RUNTIME) {
-                        taskBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
-                    }
-                    if (runtimes.second != TaskStatus.NO_LATEST_RUNTIME) {
-                        taskBuilder.setOverrideDeadline(
-                                runtimes.second - SystemClock.elapsedRealtime());
-                    }
-                } catch (NumberFormatException e) {
-                    Slog.d(TAG, "Error reading task execution criteria, skipping.");
-                    return null;
-                }
-            } else {
-                if (DEBUG) {
-                    Slog.d(TAG, "Invalid parameter tag, skipping - " + parser.getName());
-                }
-                // Expecting a parameters start tag.
-                return null;
-            }
-            maybeBuildBackoffPolicyFromXml(taskBuilder, parser);
-
-            parser.nextTag(); // Consume parameters end tag.
-
-            // Read out extras Bundle.
-            do {
-                eventType = parser.next();
-            } while (eventType == XmlPullParser.TEXT);
-            if (!(eventType == XmlPullParser.START_TAG && XML_TAG_EXTRAS.equals(parser.getName()))) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Error reading extras, skipping.");
-                }
-                return null;
-            }
-
-            PersistableBundle extras = PersistableBundle.restoreFromXml(parser);
-            taskBuilder.setExtras(extras);
-            parser.nextTag(); // Consume </extras>
-
-            return new TaskStatus(taskBuilder.build(), uid, runtimes.first, runtimes.second);
-        }
-
-        private Task.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
-            // Pull out required fields from <task> attributes.
-            int taskId = Integer.valueOf(parser.getAttributeValue(null, "taskid"));
-            String packageName = parser.getAttributeValue(null, "package");
-            String className = parser.getAttributeValue(null, "class");
-            ComponentName cname = new ComponentName(packageName, className);
-
-            return new Task.Builder(taskId, cname);
-        }
-
-        private void buildConstraintsFromXml(Task.Builder taskBuilder, XmlPullParser parser) {
-            String val = parser.getAttributeValue(null, "unmetered");
-            if (val != null) {
-                taskBuilder.setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED);
-            }
-            val = parser.getAttributeValue(null, "connectivity");
-            if (val != null) {
-                taskBuilder.setRequiredNetworkCapabilities(Task.NetworkType.ANY);
-            }
-            val = parser.getAttributeValue(null, "idle");
-            if (val != null) {
-                taskBuilder.setRequiresDeviceIdle(true);
-            }
-            val = parser.getAttributeValue(null, "charging");
-            if (val != null) {
-                taskBuilder.setRequiresCharging(true);
-            }
-        }
-
-        /**
-         * Builds the back-off policy out of the params tag. These attributes may not exist, depending
-         * on whether the back-off was set when the task was first scheduled.
-         */
-        private void maybeBuildBackoffPolicyFromXml(Task.Builder taskBuilder, XmlPullParser parser) {
-            String val = parser.getAttributeValue(null, "initial-backoff");
-            if (val != null) {
-                long initialBackoff = Long.valueOf(val);
-                val = parser.getAttributeValue(null, "backoff-policy");
-                int backoffPolicy = Integer.valueOf(val);  // Will throw NFE which we catch higher up.
-                taskBuilder.setBackoffCriteria(initialBackoff, backoffPolicy);
-            }
-        }
-
-        /**
-         * Convenience function to read out and convert deadline and delay from xml into elapsed real
-         * time.
-         * @return A {@link android.util.Pair}, where the first value is the earliest elapsed runtime
-         * and the second is the latest elapsed runtime.
-         */
-        private Pair<Long, Long> buildExecutionTimesFromXml(XmlPullParser parser)
-                throws NumberFormatException {
-            // Pull out execution time data.
-            final long nowWallclock = System.currentTimeMillis();
-            final long nowElapsed = SystemClock.elapsedRealtime();
-
-            long earliestRunTimeElapsed = TaskStatus.NO_EARLIEST_RUNTIME;
-            long latestRunTimeElapsed = TaskStatus.NO_LATEST_RUNTIME;
-            String val = parser.getAttributeValue(null, "deadline");
-            if (val != null) {
-                long latestRuntimeWallclock = Long.valueOf(val);
-                long maxDelayElapsed =
-                        Math.max(latestRuntimeWallclock - nowWallclock, 0);
-                latestRunTimeElapsed = nowElapsed + maxDelayElapsed;
-            }
-            val = parser.getAttributeValue(null, "delay");
-            if (val != null) {
-                long earliestRuntimeWallclock = Long.valueOf(val);
-                long minDelayElapsed =
-                        Math.max(earliestRuntimeWallclock - nowWallclock, 0);
-                earliestRunTimeElapsed = nowElapsed + minDelayElapsed;
-
-            }
-            return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
-        }
-    }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
deleted file mode 100644
index a286737..0000000
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task.controllers;
-
-import android.app.task.Task;
-import android.content.ComponentName;
-import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.os.UserHandle;
-
-import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Uniquely identifies a task internally.
- * Created from the public {@link android.app.task.Task} object when it lands on the scheduler.
- * Contains current state of the requirements of the task, as well as a function to evaluate
- * whether it's ready to run.
- * This object is shared among the various controllers - hence why the different fields are atomic.
- * This isn't strictly necessary because each controller is only interested in a specific field,
- * and the receivers that are listening for global state change will all run on the main looper,
- * but we don't enforce that so this is safer.
- * @hide
- */
-public class TaskStatus {
-    public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
-    public static final long NO_EARLIEST_RUNTIME = 0L;
-
-    final Task task;
-    final int uId;
-
-    /** At reschedule time we need to know whether to update task on disk. */
-    final boolean persisted;
-
-    // Constraints.
-    final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
-    final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
-    final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
-    final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
-    final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
-    final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
-
-    /**
-     * Earliest point in the future at which this task will be eligible to run. A value of 0
-     * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
-     */
-    private long earliestRunTimeElapsedMillis;
-    /**
-     * Latest point in the future at which this task must be run. A value of {@link Long#MAX_VALUE}
-     * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
-     */
-    private long latestRunTimeElapsedMillis;
-    /** How many times this task has failed, used to compute back-off. */
-    private final int numFailures;
-
-    /** Provide a handle to the service that this task will be run on. */
-    public int getServiceToken() {
-        return uId;
-    }
-
-    private TaskStatus(Task task, int uId, boolean persisted, int numFailures) {
-        this.task = task;
-        this.uId = uId;
-        this.numFailures = numFailures;
-        this.persisted = persisted;
-    }
-
-    /** Create a newly scheduled task. */
-    public TaskStatus(Task task, int uId, boolean persisted) {
-        this(task, uId, persisted, 0);
-
-        final long elapsedNow = SystemClock.elapsedRealtime();
-
-        if (task.isPeriodic()) {
-            earliestRunTimeElapsedMillis = elapsedNow;
-            latestRunTimeElapsedMillis = elapsedNow + task.getIntervalMillis();
-        } else {
-            earliestRunTimeElapsedMillis = task.hasEarlyConstraint() ?
-                    elapsedNow + task.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
-            latestRunTimeElapsedMillis = task.hasLateConstraint() ?
-                    elapsedNow + task.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
-        }
-    }
-
-    /**
-     * Create a new TaskStatus that was loaded from disk. We ignore the provided
-     * {@link android.app.task.Task} time criteria because we can load a persisted periodic task
-     * from the {@link com.android.server.task.TaskStore} and still want to respect its
-     * wallclock runtime rather than resetting it on every boot.
-     * We consider a freshly loaded task to no longer be in back-off.
-     */
-    public TaskStatus(Task task, int uId, long earliestRunTimeElapsedMillis,
-                      long latestRunTimeElapsedMillis) {
-        this(task, uId, true, 0);
-
-        this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
-        this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
-    }
-
-    /** Create a new task to be rescheduled with the provided parameters. */
-    public TaskStatus(TaskStatus rescheduling, long newEarliestRuntimeElapsedMillis,
-                      long newLatestRuntimeElapsedMillis, int backoffAttempt) {
-        this(rescheduling.task, rescheduling.getUid(), rescheduling.isPersisted(), backoffAttempt);
-
-        earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
-        latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
-    }
-
-    public Task getTask() {
-        return task;
-    }
-
-    public int getTaskId() {
-        return task.getId();
-    }
-
-    public int getNumFailures() {
-        return numFailures;
-    }
-
-    public ComponentName getServiceComponent() {
-        return task.getService();
-    }
-
-    public int getUserId() {
-        return UserHandle.getUserId(uId);
-    }
-
-    public int getUid() {
-        return uId;
-    }
-
-    public PersistableBundle getExtras() {
-        return task.getExtras();
-    }
-
-    public boolean hasConnectivityConstraint() {
-        return task.getNetworkCapabilities() == Task.NetworkType.ANY;
-    }
-
-    public boolean hasUnmeteredConstraint() {
-        return task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
-    }
-
-    public boolean hasChargingConstraint() {
-        return task.isRequireCharging();
-    }
-
-    public boolean hasTimingDelayConstraint() {
-        return earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME;
-    }
-
-    public boolean hasDeadlineConstraint() {
-        return latestRunTimeElapsedMillis != NO_LATEST_RUNTIME;
-    }
-
-    public boolean hasIdleConstraint() {
-        return task.isRequireDeviceIdle();
-    }
-
-    public long getEarliestRunTime() {
-        return earliestRunTimeElapsedMillis;
-    }
-
-    public long getLatestRunTimeElapsed() {
-        return latestRunTimeElapsedMillis;
-    }
-
-    public boolean isPersisted() {
-        return persisted;
-    }
-    /**
-     * @return Whether or not this task is ready to run, based on its requirements.
-     */
-    public synchronized boolean isReady() {
-        return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
-                && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
-                && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
-                && (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
-                && (!hasIdleConstraint() || idleConstraintSatisfied.get())
-                // Also ready if the deadline has expired - special case.
-                || (hasDeadlineConstraint() && deadlineConstraintSatisfied.get());
-    }
-
-    /*@Override
-    public int hashCode() {
-        int result = getServiceComponent().hashCode();
-        result = 31 * result + task.getId();
-        result = 31 * result + uId;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof TaskStatus)) return false;
-
-        TaskStatus that = (TaskStatus) o;
-        return ((task.getId() == that.task.getId())
-                && (uId == that.uId)
-                && (getServiceComponent().equals(that.getServiceComponent())));
-    }*/
-
-    public boolean matches(int uid, int taskId) {
-        return this.task.getId() == taskId && this.uId == uid;
-    }
-
-    @Override
-    public String toString() {
-        return String.valueOf(hashCode()).substring(0, 3) + ".."
-                + ":[" + task.getService().getPackageName() + ",tId=" + task.getId()
-                + ",R=(" + earliestRunTimeElapsedMillis + "," + latestRunTimeElapsedMillis + ")"
-                + ",N=" + task.getNetworkCapabilities() + ",C=" + task.isRequireCharging()
-                + ",I=" + task.isRequireDeviceIdle() + ",F=" + numFailures
-                + (isReady() ? "(READY)" : "")
-                + "]";
-    }
-    // Dumpsys infrastructure
-    public void dump(PrintWriter pw, String prefix) {
-        pw.println(this.toString());
-    }
-}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 32546df..b9ef492 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -186,12 +186,16 @@
                 if (resolveInfo.serviceInfo == null) continue;
 
                 String packageName = resolveInfo.serviceInfo.packageName;
+                // STOPSHIP Reenable this check once the GMS Core prebuild library has the
+                // permission.
+                /*
                 if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
                         != PackageManager.PERMISSION_GRANTED) {
                     Log.w(TAG, "Skipping agent because package " + packageName
                             + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
                     continue;
                 }
+                */
 
                 ComponentName name = getComponentName(resolveInfo);
                 if (!enabledAgents.contains(name)) continue;
diff --git a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 55dd4ab..24318df 100644
--- a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -42,6 +42,7 @@
     private static final String seappContextsPath = "seapp_contexts";
     private static final String versionPath = "selinux_version";
     private static final String macPermissionsPath = "mac_permissions.xml";
+    private static final String serviceContextsPath = "service_contexts";
 
     public SELinuxPolicyInstallReceiver() {
         super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
@@ -65,6 +66,9 @@
 
         new File(contexts, sepolicyPath).renameTo(
                 new File(contexts, sepolicyPath + "_backup"));
+
+        new File(contexts, serviceContextsPath).renameTo(
+                new File(contexts, serviceContextsPath + "_backup"));
     }
 
     private void copyUpdate(File contexts) {
@@ -74,6 +78,7 @@
         new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
         new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
         new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
+        new File(updateDir, serviceContextsPath).renameTo(new File(contexts, serviceContextsPath));
     }
 
     private int readInt(BufferedInputStream reader) throws IOException {
@@ -85,13 +90,14 @@
     }
 
     private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
-        int[] chunks = new int[6];
+        int[] chunks = new int[7];
         chunks[0] = readInt(bundle);
         chunks[1] = readInt(bundle);
         chunks[2] = readInt(bundle);
         chunks[3] = readInt(bundle);
         chunks[4] = readInt(bundle);
         chunks[5] = readInt(bundle);
+        chunks[6] = readInt(bundle);
         return chunks;
     }
 
@@ -112,6 +118,7 @@
             installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[3]);
             installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[4]);
             installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[5]);
+            installFile(new File(updateDir, serviceContextsPath), stream, chunkLengths[6]);
         } finally {
             IoUtils.closeQuietly(stream);
         }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index cfd09e5..d05d0c7 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -44,6 +44,7 @@
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
+import android.view.ViewConfiguration;
 import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.WindowManagerInternal.MagnificationCallbacks;
@@ -113,13 +114,13 @@
             mDisplayMagnifier.setMagnificationSpecLocked(spec);
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
-    public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
         if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle, immediate);
+            mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
         }
         // Not relevant for the window observer.
     }
@@ -129,7 +130,7 @@
             mDisplayMagnifier.onWindowLayersChangedLocked();
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -138,7 +139,7 @@
             mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -154,7 +155,7 @@
             mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -162,7 +163,16 @@
         // Not relevant for the display magnifier.
 
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        }
+    }
+
+
+    public void onSomeWindowResizedOrMovedLocked() {
+        // Not relevant for the display magnifier.
+
+        if (mWindowsForAccessibilityObserver != null) {
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -247,7 +257,7 @@
             mWindowManagerService.scheduleAnimationLocked();
         }
 
-        public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+        public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
             if (DEBUG_RECTANGLE_REQUESTED) {
                 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
             }
@@ -880,21 +890,45 @@
 
         private final WindowsForAccessibilityCallback mCallback;
 
+        private final long mRecurringAccessibilityEventsIntervalMillis;
+
         public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
                 WindowsForAccessibilityCallback callback) {
             mContext = windowManagerService.mContext;
             mWindowManagerService = windowManagerService;
             mCallback = callback;
             mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
+            mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
+                    .getSendRecurringAccessibilityEventsInterval();
             computeChangedWindows();
         }
 
+        public void scheduleComputeChangedWindowsLocked() {
+            // If focus changed, compute changed windows immediately as the focused window
+            // is used by the accessibility manager service to determine the active window.
+            if (mWindowManagerService.mCurrentFocus != null
+                    && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
+                mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
+                computeChangedWindows();
+            } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
+                mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
+                        mRecurringAccessibilityEventsIntervalMillis);
+            }
+        }
+
         public void computeChangedWindows() {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "computeChangedWindows()");
             }
 
             synchronized (mWindowManagerService.mWindowMap) {
+                // Do not send the windows if there is no current focus as
+                // the window manager is still looking for where to put it.
+                // We will do the work when we get a focus change callback.
+                if (mWindowManagerService.mCurrentFocus == null) {
+                    return;
+                }
+
                 WindowManager windowManager = (WindowManager)
                         mContext.getSystemService(Context.WINDOW_SERVICE);
                 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
@@ -912,39 +946,21 @@
                 Set<IBinder> addedWindows = mTempBinderSet;
                 addedWindows.clear();
 
+                boolean focusedWindowAdded = false;
+
                 final int visibleWindowCount = visibleWindows.size();
                 for (int i = visibleWindowCount - 1; i >= 0; i--) {
                     WindowState windowState = visibleWindows.valueAt(i);
-                    // Compute the window touchable frame as shown on the screen.
 
-                    // Get the touchable frame.
-                    Region touchableRegion = mTempRegion1;
-                    windowState.getTouchableRegion(touchableRegion);
-                    Rect touchableFrame = mTempRect;
-                    touchableRegion.getBounds(touchableFrame);
-
-                    // Move to origin as all transforms are captured by the matrix.
-                    RectF windowFrame = mTempRectF;
-                    windowFrame.set(touchableFrame);
-                    windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
-
-                    // Map the frame to get what appears on the screen.
-                    Matrix matrix = mTempMatrix;
-                    populateTransformationMatrixLocked(windowState, matrix);
-                    matrix.mapRect(windowFrame);
-
-                    // Got the bounds.
+                    // Compute the bounds in the screen.
                     Rect boundsInScreen = mTempRect;
-                    boundsInScreen.set((int) windowFrame.left, (int) windowFrame.top,
-                            (int) windowFrame.right, (int) windowFrame.bottom);
+                    computeWindowBoundsInScreen(windowState, boundsInScreen);
 
                     final int flags = windowState.mAttrs.flags;
 
                     // If the window is not touchable, do not report it but take into account
                     // the space it takes since the content behind it cannot be touched.
-                    if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 1) {
-                        unaccountedSpace.op(boundsInScreen, unaccountedSpace,
-                                Region.Op.DIFFERENCE);
+                    if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
                         continue;
                     }
 
@@ -956,33 +972,12 @@
                     // Add windows of certain types not covered by modal windows.
                     if (isReportedWindowType(windowState.mAttrs.type)) {
                         // Add the window to the ones to be reported.
-                        WindowInfo window = WindowInfo.obtain();
-                        window.type = windowState.mAttrs.type;
-                        window.layer = windowState.mLayer;
-                        window.token = windowState.mClient.asBinder();
-
+                        WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
                         addedWindows.add(window.token);
-
-                        WindowState attachedWindow = windowState.mAttachedWindow;
-                        if (attachedWindow != null) {
-                            window.parentToken = attachedWindow.mClient.asBinder();
-                        }
-
-                        window.focused = windowState.isFocused();
-                        window.boundsInScreen.set(boundsInScreen);
-
-                        final int childCount = windowState.mChildWindows.size();
-                        if (childCount > 0) {
-                            if (window.childTokens == null) {
-                                window.childTokens = new ArrayList<IBinder>();
-                            }
-                            for (int j = 0; j < childCount; j++) {
-                                WindowState child = windowState.mChildWindows.get(j);
-                                window.childTokens.add(child.mClient.asBinder());
-                            }
-                        }
-
                         windows.add(window);
+                        if (windowState.isFocused()) {
+                            focusedWindowAdded = true;
+                        }
                     }
 
                     // Account for the space this window takes.
@@ -1001,6 +996,25 @@
                     }
                 }
 
+                // Always report the focused window.
+                if (!focusedWindowAdded) {
+                    for (int i = visibleWindowCount - 1; i >= 0; i--) {
+                        WindowState windowState = visibleWindows.valueAt(i);
+                        if (windowState.isFocused()) {
+                            // Compute the bounds in the screen.
+                            Rect boundsInScreen = mTempRect;
+                            computeWindowBoundsInScreen(windowState, boundsInScreen);
+
+                            // Add the window to the ones to be reported.
+                            WindowInfo window = obtainPopulatedWindowInfo(windowState,
+                                    boundsInScreen);
+                            addedWindows.add(window.token);
+                            windows.add(window);
+                            break;
+                        }
+                    }
+                }
+
                 // Remove child/parent references to windows that were not added.
                 final int windowCount = windows.size();
                 for (int i = 0; i < windowCount; i++) {
@@ -1063,6 +1077,57 @@
             }
         }
 
+        private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
+            // Get the touchable frame.
+            Region touchableRegion = mTempRegion1;
+            windowState.getTouchableRegion(touchableRegion);
+            Rect touchableFrame = mTempRect;
+            touchableRegion.getBounds(touchableFrame);
+
+            // Move to origin as all transforms are captured by the matrix.
+            RectF windowFrame = mTempRectF;
+            windowFrame.set(touchableFrame);
+            windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
+
+            // Map the frame to get what appears on the screen.
+            Matrix matrix = mTempMatrix;
+            populateTransformationMatrixLocked(windowState, matrix);
+            matrix.mapRect(windowFrame);
+
+            // Got the bounds.
+            outBounds.set((int) windowFrame.left, (int) windowFrame.top,
+                    (int) windowFrame.right, (int) windowFrame.bottom);
+        }
+
+        private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
+                Rect boundsInScreen) {
+            WindowInfo window = WindowInfo.obtain();
+            window.type = windowState.mAttrs.type;
+            window.layer = windowState.mLayer;
+            window.token = windowState.mClient.asBinder();
+
+            WindowState attachedWindow = windowState.mAttachedWindow;
+            if (attachedWindow != null) {
+                window.parentToken = attachedWindow.mClient.asBinder();
+            }
+
+            window.focused = windowState.isFocused();
+            window.boundsInScreen.set(boundsInScreen);
+
+            final int childCount = windowState.mChildWindows.size();
+            if (childCount > 0) {
+                if (window.childTokens == null) {
+                    window.childTokens = new ArrayList<IBinder>();
+                }
+                for (int j = 0; j < childCount; j++) {
+                    WindowState child = windowState.mChildWindows.get(j);
+                    window.childTokens.add(child.mClient.asBinder());
+                }
+            }
+
+            return window;
+        }
+
         private void cacheWindows(List<WindowInfo> windows) {
             final int oldWindowCount = mOldWindows.size();
             for (int i = oldWindowCount - 1; i >= 0; i--) {
@@ -1079,10 +1144,10 @@
             if (oldWindow == newWindow) {
                 return false;
             }
-            if (oldWindow == null && newWindow != null) {
+            if (oldWindow == null) {
                 return true;
             }
-            if (oldWindow != null && newWindow == null) {
+            if (newWindow == null) {
                 return true;
             }
             if (oldWindow.type != newWindow.type) {
@@ -1151,7 +1216,8 @@
         }
 
         private class MyHandler extends Handler {
-            public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 1;
+            public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
+            public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
 
             public MyHandler(Looper looper) {
                 super(looper, null, false);
@@ -1161,6 +1227,10 @@
             @SuppressWarnings("unchecked")
             public void handleMessage(Message message) {
                 switch (message.what) {
+                    case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
+                        computeChangedWindows();
+                    } break;
+
                     case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
                         List<WindowInfo> windows = (List<WindowInfo>) message.obj;
                         mCallback.onWindowsForAccessibilityChanged(windows);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3200b54..b4cf2ae 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -446,11 +446,11 @@
         }
     }
 
-    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized(mService.mWindowMap) {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mService.onRectangleOnScreenRequested(token, rectangle, immediate);
+                mService.onRectangleOnScreenRequested(token, rectangle);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a354c45..dfb1200 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -154,7 +154,8 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                    if (windows.get(winNdx).mWinAnimator.isAnimating()) {
+                    final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
+                    if (winAnimator.isAnimating() && !winAnimator.isDummyAnimation()) {
                         return true;
                     }
                 }
@@ -236,9 +237,22 @@
 
     void detachDisplay() {
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+
+        boolean doAnotherLayoutPass = false;
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx));
+            final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
+            for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
+                final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
+                for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
+                    mService.removeWindowInnerLocked(null, appWindows.get(winNdx));
+                    doAnotherLayoutPass = true;
+                }
+            }
         }
+        if (doAnotherLayoutPass) {
+            mService.requestTraversalLocked();
+        }
+
         mAnimationBackgroundSurface.destroySurface();
         mAnimationBackgroundSurface = null;
         mDimLayer.destroySurface();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 008d2fc..45326f7 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
@@ -227,7 +228,7 @@
                     continue;
                 }
                 final WindowStateAnimator winAnimator = win.mWinAnimator;
-                if (mPolicy.doesForceHide(win.mAttrs)) {
+                if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                     if (!winAnimator.mAnimating) {
                         // Create a new animation to delay until keyguard is gone on its own.
                         winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
@@ -268,7 +269,7 @@
                     }
                 }
 
-                if (mPolicy.doesForceHide(win.mAttrs)) {
+                if (mPolicy.isForceHiding(win.mAttrs)) {
                     if (!wasAnimating && nowAnimating) {
                         if (WindowManagerService.DEBUG_ANIM ||
                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c5d7a54..2d8a34b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -151,7 +151,6 @@
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
@@ -2530,7 +2529,7 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private void removeWindowInnerLocked(Session session, WindowState win) {
+    void removeWindowInnerLocked(Session session, WindowState win) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2812,14 +2811,13 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
-    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized (mWindowMap) {
             if (mAccessibilityController != null) {
                 WindowState window = mWindowMap.get(token);
                 //TODO (multidisplay): Magnification is supported only for the default display.
                 if (window != null && window.getDisplayId() == Display.DEFAULT_DISPLAY) {
-                    mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle,
-                            immediate);
+                    mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle);
                 }
             }
         }
@@ -8444,7 +8442,7 @@
                     }
                     win.mLayoutNeeded = false;
                     win.prelayout();
-                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
+                    mPolicy.layoutWindowLw(win, null);
                     win.mLayoutSeq = seq;
                     if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
                             + win.mFrame + " mContainingFrame="
@@ -8496,7 +8494,7 @@
                     }
                     win.mLayoutNeeded = false;
                     win.prelayout();
-                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+                    mPolicy.layoutWindowLw(win, win.mAttachedWindow);
                     win.mLayoutSeq = seq;
                     if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
                             + win.mFrame + " mContainingFrame="
@@ -9228,6 +9226,13 @@
                         winAnimator.setAnimation(a);
                         winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
                         winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+
+                        //TODO (multidisplay): Accessibility supported only for the default display.
+                        if (mAccessibilityController != null
+                                && displayId == Display.DEFAULT_DISPLAY) {
+                            mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                        }
+
                         try {
                             w.mClient.moved(w.mFrame.left, w.mFrame.top);
                         } catch (RemoteException e) {
@@ -9866,7 +9871,9 @@
             mCurrentFocus = newFocus;
             mLosingFocus.remove(newFocus);
 
-            if (mAccessibilityController != null) {
+            // TODO(multidisplay): Accessibilty supported only of default desiplay.
+            if (mAccessibilityController != null
+                    && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
                 mAccessibilityController.onWindowFocusChangedLocked();
             }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4a80e3e..7003c8c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -36,6 +36,7 @@
 import android.os.RemoteCallbackList;
 import android.os.SystemClock;
 import android.util.TimeUtils;
+import android.view.Display;
 import android.view.IWindowFocusObserver;
 import android.view.IWindowId;
 import com.android.server.input.InputWindowHandle;
@@ -727,8 +728,11 @@
     }
 
     public DisplayContent getDisplayContent() {
-        return mAppToken == null || mNotOnAppsDisplay ?
-                mDisplayContent : getStack().getDisplayContent();
+        if (mAppToken == null || mNotOnAppsDisplay) {
+            return mDisplayContent;
+        }
+        final TaskStack stack = getStack();
+        return stack == null ? mDisplayContent : stack.getDisplayContent();
     }
 
     public int getDisplayId() {
@@ -1359,6 +1363,13 @@
                 mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
                         newConfig);
             }
+
+            //TODO (multidisplay): Accessibility supported only for the default display.
+            if (mService.mAccessibilityController != null
+                    && getDisplayId() == Display.DEFAULT_DISPLAY) {
+                mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+            }
+
             mOverscanInsetsChanged = false;
             mContentInsetsChanged = false;
             mVisibleInsetsChanged = false;
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index a734026..0f919d1 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -57,12 +57,21 @@
     int getVersion();
     // Get vendor id used for vendor command.
     uint32_t getVendorId();
+    // Get Port information on all the HDMI ports.
+    jobjectArray getPortInfos();
+    // Set a flag and its value.
+    void setOption(int flag, int value);
+    // Set audio return channel status.
+    void setAudioReturnChannel(bool flag);
+    // Whether to hdmi device is connected to the given port.
+    bool isConnected(int port);
 
     jobject getCallbacksObj() const {
         return mCallbacksObj;
     }
 
 private:
+    static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
     static void onReceived(const hdmi_event_t* event, void* arg);
 
     hdmi_cec_device_t* mDevice;
@@ -203,11 +212,11 @@
 }
 
 int HdmiCecController::getPhysicalAddress() {
-    uint16_t physicalAddress = 0xFFFF;
-    if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) {
-        return physicalAddress;
+    uint16_t addr;
+    if (!mDevice->get_physical_address(mDevice, &addr)) {
+        return addr;
     }
-    return -1;
+    return INVALID_PHYSICAL_ADDRESS;
 }
 
 int HdmiCecController::getVersion() {
@@ -222,6 +231,47 @@
     return vendorId;
 }
 
+jobjectArray HdmiCecController::getPortInfos() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
+    if (hdmiPortInfo == NULL) {
+        return NULL;
+    }
+    jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V");
+    if (ctor == NULL) {
+        return NULL;
+    }
+    hdmi_port_info* ports;
+    int numPorts;
+    mDevice->get_port_info(mDevice, &ports, &numPorts);
+    jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
+
+    // MHL support field will be obtained from MHL HAL. Leave it to false.
+    jboolean mhlSupported = (jboolean) 0;
+    for (int i = 0; i < numPorts; ++i) {
+        hdmi_port_info* info = &ports[i];
+        jboolean cecSupported = (jboolean) info->cec_supported;
+        jboolean arcSupported = (jboolean) info->arc_supported;
+        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_num, info->type,
+                info->physical_address, cecSupported, mhlSupported, arcSupported);
+        env->SetObjectArrayElement(res, i, infoObj);
+    }
+    return res;
+}
+
+void HdmiCecController::setOption(int flag, int value) {
+    mDevice->set_option(mDevice, flag, value);
+}
+
+// Set audio return channel status.
+void HdmiCecController::setAudioReturnChannel(bool enabled) {
+    mDevice->set_audio_return_channel(mDevice, enabled ? 1 : 0);
+}
+
+// Whether to hdmi device is connected to the given port.
+bool HdmiCecController::isConnected(int port) {
+    return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
+}
 
 // static
 void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
@@ -291,41 +341,53 @@
     return controller->sendMessage(message);
 }
 
-static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz,
-        jlong controllerPtr, jint logicalAddress) {
-    HdmiCecController* controller =
-            reinterpret_cast<HdmiCecController*>(controllerPtr);
-    return controller->addLogicalAddress(
-            static_cast<cec_logical_address_t>(logicalAddress));
+static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
+        jint logicalAddress) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
 }
 
-static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz,
-        jlong controllerPtr) {
-    HdmiCecController* controller =
-            reinterpret_cast<HdmiCecController*>(controllerPtr);
+static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
     controller->clearLogicaladdress();
 }
 
-static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz,
-        jlong controllerPtr) {
-    HdmiCecController* controller =
-            reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
     return controller->getPhysicalAddress();
 }
 
-static jint nativeGetVersion(JNIEnv* env, jclass clazz,
-        jlong controllerPtr) {
-    HdmiCecController* controller =
-            reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
     return controller->getVersion();
 }
 
 static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
-    HdmiCecController* controller =
-            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
     return controller->getVendorId();
 }
 
+static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->getPortInfos();
+}
+
+static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    controller->setOption(flag, value);
+}
+
+static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
+        jboolean enabled) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    controller->setAudioReturnChannel(enabled == JNI_TRUE);
+}
+
+static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
+}
+
 static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
@@ -337,13 +399,18 @@
     { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
     { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
     { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
+    { "nativeGetPortInfos",
+      "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
+      (void *) nativeGetPortInfos },
+    { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
+    { "nativeSetAudioReturnChannel", "(JZ)V", (void *) nativeSetAudioReturnChannel },
+    { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
 };
 
 #define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
 
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods,
-            NELEM(sMethods));
+    int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
     return 0;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5cfe0f1..4574caf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -32,6 +32,7 @@
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
+import android.app.IActivityManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -818,12 +819,20 @@
         }
 
         if (who != null) {
+            if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
+                throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+                         + " does not own the device");
+            }
+            if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
+                throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+                        + " does not own the profile");
+            }
             throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
                     + " did not specify uses-policy for: "
                     + candidates.get(0).info.getTagForPolicy(reqPolicy));
         } else {
             throw new SecurityException("No active admin owned by uid "
-                    + Binder.getCallingUid() + " for policy:" + reqPolicy);
+                    + Binder.getCallingUid() + " for policy #" + reqPolicy);
         }
     }
 
@@ -831,15 +840,23 @@
         sendAdminCommandLocked(admin, action, null);
     }
 
+    void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
+        sendAdminCommandLocked(admin, action, null, result);
+    }
+
     /**
      * Send an update to one specific admin, get notified when that admin returns a result.
      */
-    void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
+    void sendAdminCommandLocked(ActiveAdmin admin, String action, Bundle adminExtras,
+            BroadcastReceiver result) {
         Intent intent = new Intent(action);
         intent.setComponent(admin.info.getComponent());
         if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
             intent.putExtra("expiration", admin.passwordExpirationDate);
         }
+        if (adminExtras != null) {
+            intent.putExtras(adminExtras);
+        }
         if (result != null) {
             mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
                     null, result, mHandler, Activity.RESULT_OK, null, null);
@@ -1367,6 +1384,11 @@
         if (!mHasFeature) {
             return;
         }
+        setActiveAdmin(adminReceiver, refreshing, userHandle, null);
+    }
+
+    private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
+            Bundle onEnableData) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
         enforceCrossUserPermission(userHandle);
@@ -1403,7 +1425,8 @@
                     policy.mAdminList.set(replaceIndex, newAdmin);
                 }
                 saveSettingsLocked(userHandle);
-                sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
+                sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+                        onEnableData, null);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -3490,6 +3513,36 @@
     }
 
     @Override
+    public UserHandle createAndInitializeUser(ComponentName who, String name,
+            String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
+        UserHandle user = createUser(who, name);
+        long id = Binder.clearCallingIdentity();
+        try {
+            String profileOwnerPkg = profileOwnerComponent.getPackageName();
+            final IPackageManager ipm = AppGlobals.getPackageManager();
+            IActivityManager activityManager = ActivityManagerNative.getDefault();
+
+            try {
+                // Install the profile owner if not present.
+                if (!ipm.isPackageAvailable(profileOwnerPkg, user.getIdentifier())) {
+                    ipm.installExistingPackageAsUser(profileOwnerPkg, user.getIdentifier());
+                }
+
+                // Start user in background.
+                activityManager.startUserInBackground(user.getIdentifier());
+            } catch (RemoteException e) {
+                Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
+            }
+
+            setActiveAdmin(profileOwnerComponent, true, user.getIdentifier(), adminExtras);
+            setProfileOwner(profileOwnerPkg, ownerName, user.getIdentifier());
+            return user;
+        } finally {
+            restoreCallingIdentity(id);
+        }
+    }
+
+    @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
         synchronized (this) {
             if (who == null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bb61b81..f946595 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -44,6 +44,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.service.dreams.DreamService;
+import android.service.fingerprint.FingerprintManager;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -63,8 +64,10 @@
 import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
+import com.android.server.fingerprint.FingerprintService;
 import com.android.server.hdmi.HdmiControlService;
 import com.android.server.input.InputManagerService;
+import com.android.server.job.JobSchedulerService;
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LightsService;
 import com.android.server.media.MediaRouterService;
@@ -84,7 +87,6 @@
 import com.android.server.search.SearchManagerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
-import com.android.server.task.TaskManagerService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.twilight.TwilightService;
@@ -132,8 +134,8 @@
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String ETHERNET_SERVICE_CLASS =
             "com.android.server.ethernet.EthernetService";
-    private static final String TASK_SERVICE_CLASS =
-            "com.android.server.task.TaskManagerService";
+    private static final String JOB_SCHEDULER_SERVICE_CLASS =
+            "com.android.server.job.JobSchedulerService";
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
@@ -349,6 +351,7 @@
         boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
         boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
         boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
+        boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
         try {
             Slog.i(TAG, "Telephony Registry");
@@ -461,7 +464,7 @@
             // Skip Bluetooth if we have an emulator kernel
             // TODO: Use a more reliable check to see if this product should
             // support Bluetooth - see bug 988521
-            if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
+            if (isEmulator) {
                 Slog.i(TAG, "No Bluetooh Service (emulator)");
             } else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 Slog.i(TAG, "No Bluetooth Service (factory test)");
@@ -662,10 +665,17 @@
                     reportWtf("starting Wi-Fi Scanning Service", e);
                 }
 
-                try {
-                    mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
-                } catch (Throwable e) {
-                    reportWtf("starting Ethernet Service", e);
+                if (!isEmulator) {
+                    try {
+                        mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
+                    } catch (Throwable e) {
+                        reportWtf("starting Ethernet Service", e);
+                    }
+                } else {
+                    // Don't start the Ethernet service on the emulator because
+                    // it interferes with qemu's SLIRP emulation, which uses
+                    // IPv4 over eth0. http://b/15341003 .
+                    Slog.i(TAG, "Not starting Ethernet service (emulator)");
                 }
 
                 try {
@@ -826,7 +836,7 @@
 
             mSystemServiceManager.startService(UiModeManagerService.class);
 
-            mSystemServiceManager.startService(TaskManagerService.class);
+            mSystemServiceManager.startService(JobSchedulerService.class);
 
             if (!disableNonCoreServices) {
                 try {
@@ -925,13 +935,6 @@
             }
 
             try {
-                Slog.i(TAG, "IdleMaintenanceService");
-                new IdleMaintenanceService(context, battery);
-            } catch (Throwable e) {
-                reportWtf("starting IdleMaintenanceService", e);
-            }
-
-            try {
                 if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
                     mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
                 }
@@ -981,11 +984,19 @@
                 }
 
                 try {
+                    Slog.i(TAG, "Fingerprint Manager");
+                    mSystemServiceManager.startService(FingerprintService.class);
+                } catch (Throwable e) {
+                    Slog.e(TAG, "Failure starting FingerprintService", e);
+                }
+
+                try {
                     Slog.i(TAG, "BackgroundDexOptService");
-                    new BackgroundDexOptService(context);
+                    BackgroundDexOptService.schedule(context);
                 } catch (Throwable e) {
                     reportWtf("starting BackgroundDexOptService", e);
                 }
+
             }
 
             try {
diff --git a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java b/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
index e7f9ca0..7a7fa07 100644
--- a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
@@ -3,18 +3,19 @@
 
 import android.content.ComponentName;
 import android.content.Context;
-import android.app.task.Task;
-import android.app.task.Task.Builder;
+import android.app.job.JobInfo;
+import android.app.job.JobInfo.Builder;
 import android.os.PersistableBundle;
 import android.test.AndroidTestCase;
 import android.test.RenamingDelegatingContext;
 import android.util.Log;
 
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.JobMapReadFinishedListener;
+import com.android.server.job.JobStore;
+import com.android.server.job.controllers.JobStatus;
 
 import java.util.List;
 
-import static com.android.server.task.TaskStore.initAndGet;
 /**
  * Test reading and writing correctly from file.
  */
@@ -26,12 +27,12 @@
     private ComponentName mComponent;
     private static final long IO_WAIT = 600L;
 
-    TaskStore mTaskStoreUnderTest;
+    JobStore mTaskStoreUnderTest;
     Context mTestContext;
-    TaskMapReadFinishedListener mTaskMapReadFinishedListenerStub =
-            new TaskMapReadFinishedListener() {
+    JobMapReadFinishedListener mTaskMapReadFinishedListenerStub =
+            new JobMapReadFinishedListener() {
         @Override
-        public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+        public void onJobMapReadFinished(List<JobStatus> tasks) {
             // do nothing.
         }
     };
@@ -40,7 +41,7 @@
     public void setUp() throws Exception {
         mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
         Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
-        mTaskStoreUnderTest = TaskStore.initAndGetForTesting(mTestContext,
+        mTaskStoreUnderTest = JobStore.initAndGetForTesting(mTestContext,
                 mTestContext.getFilesDir(), mTaskMapReadFinishedListenerStub);
         mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
     }
@@ -56,23 +57,23 @@
         long runFromMillis = 2000L; // 2s
         long initialBackoff = 10000L; // 10s
 
-        final Task task = new Builder(taskId, mComponent)
+        final JobInfo task = new Builder(taskId, mComponent)
                 .setRequiresCharging(true)
-                .setRequiredNetworkCapabilities(Task.NetworkType.ANY)
-                .setBackoffCriteria(initialBackoff, Task.BackoffPolicy.EXPONENTIAL)
+                .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)
+                .setBackoffCriteria(initialBackoff, JobInfo.BackoffPolicy.EXPONENTIAL)
                 .setOverrideDeadline(runByMillis)
                 .setMinimumLatency(runFromMillis)
                 .build();
-        final TaskStatus ts = new TaskStatus(task, SOME_UID, true /* persisted */);
+        final JobStatus ts = new JobStatus(task, SOME_UID, true /* persisted */);
         mTaskStoreUnderTest.add(ts);
         Thread.sleep(IO_WAIT);
         // Manually load tasks from xml file.
-        mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+        mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
             @Override
-            public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+            public void onJobMapReadFinished(List<JobStatus> tasks) {
                 assertEquals("Didn't get expected number of persisted tasks.", 1, tasks.size());
-                TaskStatus loadedTaskStatus = tasks.get(0);
-                assertTasksEqual(task, loadedTaskStatus.getTask());
+                JobStatus loadedTaskStatus = tasks.get(0);
+                assertTasksEqual(task, loadedTaskStatus.getJob());
                 assertEquals("Different uids.", SOME_UID, tasks.get(0).getUid());
                 compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
                         ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
@@ -84,30 +85,30 @@
     }
 
     public void testWritingTwoFilesToDisk() throws Exception {
-        final Task task1 = new Builder(8, mComponent)
+        final JobInfo task1 = new Builder(8, mComponent)
                 .setRequiresDeviceIdle(true)
                 .setPeriodic(10000L)
                 .setRequiresCharging(true)
                 .build();
-        final Task task2 = new Builder(12, mComponent)
+        final JobInfo task2 = new Builder(12, mComponent)
                 .setMinimumLatency(5000L)
-                .setBackoffCriteria(15000L, Task.BackoffPolicy.LINEAR)
+                .setBackoffCriteria(15000L, JobInfo.BackoffPolicy.LINEAR)
                 .setOverrideDeadline(30000L)
-                .setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED)
+                .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
                 .build();
-        final TaskStatus taskStatus1 = new TaskStatus(task1, SOME_UID, true /* persisted */);
-        final TaskStatus taskStatus2 = new TaskStatus(task2, SOME_UID, true /* persisted */);
+        final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID, true /* persisted */);
+        final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID, true /* persisted */);
         mTaskStoreUnderTest.add(taskStatus1);
         mTaskStoreUnderTest.add(taskStatus2);
         Thread.sleep(IO_WAIT);
-        mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+        mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
             @Override
-            public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+            public void onJobMapReadFinished(List<JobStatus> tasks) {
                 assertEquals("Incorrect # of persisted tasks.", 2, tasks.size());
-                TaskStatus loaded1 = tasks.get(0);
-                TaskStatus loaded2 = tasks.get(1);
-                assertTasksEqual(task1, loaded1.getTask());
-                assertTasksEqual(task2, loaded2.getTask());
+                JobStatus loaded1 = tasks.get(0);
+                JobStatus loaded2 = tasks.get(1);
+                assertTasksEqual(task1, loaded1.getJob());
+                assertTasksEqual(task2, loaded2.getJob());
 
                 // Check that the loaded task has the correct runtimes.
                 compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
@@ -124,7 +125,7 @@
     }
 
     public void testWritingTaskWithExtras() throws Exception {
-        Task.Builder b = new Builder(8, mComponent)
+        JobInfo.Builder b = new Builder(8, mComponent)
                 .setRequiresDeviceIdle(true)
                 .setPeriodic(10000L)
                 .setRequiresCharging(true);
@@ -134,17 +135,17 @@
         extras.putString("hi", "there");
         extras.putInt("into", 3);
         b.setExtras(extras);
-        final Task task = b.build();
-        TaskStatus taskStatus = new TaskStatus(task, SOME_UID, true /* persisted */);
+        final JobInfo task = b.build();
+        JobStatus taskStatus = new JobStatus(task, SOME_UID, true /* persisted */);
 
         mTaskStoreUnderTest.add(taskStatus);
         Thread.sleep(IO_WAIT);
-        mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+        mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
             @Override
-            public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+            public void onJobMapReadFinished(List<JobStatus> tasks) {
                 assertEquals("Incorrect # of persisted tasks.", 1, tasks.size());
-                TaskStatus loaded = tasks.get(0);
-                assertTasksEqual(task, loaded.getTask());
+                JobStatus loaded = tasks.get(0);
+                assertTasksEqual(task, loaded.getJob());
             }
         });
 
@@ -153,7 +154,7 @@
     /**
      * Helper function to throw an error if the provided task and TaskStatus objects are not equal.
      */
-    private void assertTasksEqual(Task first, Task second) {
+    private void assertTasksEqual(JobInfo first, JobInfo second) {
         assertEquals("Different task ids.", first.getId(), second.getId());
         assertEquals("Different components.", first.getService(), second.getService());
         assertEquals("Different periodic status.", first.isPeriodic(), second.isPeriodic());
@@ -168,11 +169,11 @@
         assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
                 second.isRequireDeviceIdle());
         assertEquals("Invalid unmetered constraint.",
-                first.getNetworkCapabilities() == Task.NetworkType.UNMETERED,
-                second.getNetworkCapabilities() == Task.NetworkType.UNMETERED);
+                first.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED,
+                second.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED);
         assertEquals("Invalid connectivity constraint.",
-                first.getNetworkCapabilities() == Task.NetworkType.ANY,
-                second.getNetworkCapabilities() == Task.NetworkType.ANY);
+                first.getNetworkCapabilities() == JobInfo.NetworkType.ANY,
+                second.getNetworkCapabilities() == JobInfo.NetworkType.ANY);
         assertEquals("Invalid deadline constraint.",
                 first.hasLateConstraint(),
                 second.hasLateConstraint());
diff --git a/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java b/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
deleted file mode 100644
index 6617a05..0000000
--- a/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.task.controllers;
-
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-
-import com.android.server.task.StateChangedListener;
-
-import static com.android.server.task.controllers.BatteryController.getForTesting;
-
-import static org.mockito.Mockito.*;
-
-/**
- *
- */
-public class BatteryControllerTest extends AndroidTestCase {
-    BatteryController mBatteryControllerUnderTest;
-
-    StateChangedListener mStateChangedListenerStub = new StateChangedListener() {
-        @Override
-        public void onControllerStateChanged() {
-
-        }
-
-        @Override
-        public void onRunTaskNow(TaskStatus taskStatus) {
-
-        }
-    };
-    BatteryController.ChargingTracker mTrackerUnderTest;
-
-    public void setUp() throws Exception {
-        mBatteryControllerUnderTest = getForTesting(mStateChangedListenerStub, getTestContext());
-        mTrackerUnderTest = mBatteryControllerUnderTest.getTracker();
-    }
-
-    public void testSendBatteryChargingIntent() throws Exception {
-        Intent batteryConnectedIntent = new Intent(Intent.ACTION_POWER_CONNECTED)
-                .setComponent(new ComponentName(getContext(), mTrackerUnderTest.getClass()));
-        Intent batteryHealthyIntent = new Intent(Intent.ACTION_BATTERY_OKAY)
-                .setComponent(new ComponentName(getContext(), mTrackerUnderTest.getClass()));
-
-        mTrackerUnderTest.onReceiveInternal(batteryConnectedIntent);
-        mTrackerUnderTest.onReceiveInternal(batteryHealthyIntent);
-
-        assertTrue(mTrackerUnderTest.isOnStablePower());
-    }
-
-}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/CallCapabilities.java b/telecomm/java/android/telecomm/CallCapabilities.java
index b2b33a3..5aff19c 100644
--- a/telecomm/java/android/telecomm/CallCapabilities.java
+++ b/telecomm/java/android/telecomm/CallCapabilities.java
@@ -17,7 +17,7 @@
 package android.telecomm;
 
 /** Defines actions a call currently supports. */
-public class CallCapabilities {
+public final class CallCapabilities {
     /** Call can currently be put on hold or unheld. */
     public static final int HOLD               = 0x00000001;
 
@@ -27,24 +27,60 @@
     /** Call can currently be merged. */
     public static final int MERGE_CALLS        = 0x00000004;
 
-     /* Call can currently be swapped with another call. */
+    /** Call can currently be swapped with another call. */
     public static final int SWAP_CALLS         = 0x00000008;
 
-     /* Call currently supports adding another call to this one. */
+    /** Call currently supports adding another call to this one. */
     public static final int ADD_CALL           = 0x00000010;
 
-     /* Call supports responding via text option. */
+    /** Call supports responding via text option. */
     public static final int RESPOND_VIA_TEXT   = 0x00000020;
 
-     /* Call can be muted. */
+    /** Call can be muted. */
     public static final int MUTE               = 0x00000040;
 
-     /* Call supports generic conference mode. */
+    /** Call supports generic conference mode. */
     public static final int GENERIC_CONFERENCE = 0x00000080;
 
-     /* Call currently supports switch between connections. */
+    /** Call currently supports switch between connections. */
     public static final int CONNECTION_HANDOFF = 0x00000100;
 
     public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
             | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE | CONNECTION_HANDOFF;
+
+    public static String toString(int capabilities) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[Capabilities:");
+        if ((capabilities & HOLD) != 0) {
+            builder.append(" HOLD");
+        }
+        if ((capabilities & SUPPORT_HOLD) != 0) {
+            builder.append(" SUPPORT_HOLD");
+        }
+        if ((capabilities & MERGE_CALLS) != 0) {
+            builder.append(" MERGE_CALLS");
+        }
+        if ((capabilities & SWAP_CALLS) != 0) {
+            builder.append(" SWAP_CALLS");
+        }
+        if ((capabilities & ADD_CALL) != 0) {
+            builder.append(" ADD_CALL");
+        }
+        if ((capabilities & RESPOND_VIA_TEXT) != 0) {
+            builder.append(" RESPOND_VIA_TEXT");
+        }
+        if ((capabilities & MUTE) != 0) {
+            builder.append(" MUTE");
+        }
+        if ((capabilities & GENERIC_CONFERENCE) != 0) {
+            builder.append(" GENERIC_CONFERENCE");
+        }
+        if ((capabilities & CONNECTION_HANDOFF) != 0) {
+            builder.append(" HANDOFF");
+        }
+        builder.append("]");
+        return builder.toString();
+    }
+
+    private CallCapabilities() {}
 }
diff --git a/telecomm/java/android/telecomm/CallService.java b/telecomm/java/android/telecomm/CallService.java
index a254459..0b5981c 100644
--- a/telecomm/java/android/telecomm/CallService.java
+++ b/telecomm/java/android/telecomm/CallService.java
@@ -61,7 +61,7 @@
     private static final int MSG_ON_AUDIO_STATE_CHANGED = 11;
     private static final int MSG_PLAY_DTMF_TONE = 12;
     private static final int MSG_STOP_DTMF_TONE = 13;
-    private static final int MSG_ADD_TO_CONFERENCE = 14;
+    private static final int MSG_CONFERENCE = 14;
     private static final int MSG_SPLIT_FROM_CONFERENCE = 15;
     private static final int MSG_ON_POST_DIAL_CONTINUE = 16;
 
@@ -128,24 +128,12 @@
                 case MSG_STOP_DTMF_TONE:
                     stopDtmfTone((String) msg.obj);
                     break;
-                case MSG_ADD_TO_CONFERENCE: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    try {
-                        @SuppressWarnings("unchecked")
-                        List<String> callIds = (List<String>) args.arg2;
-                        String conferenceCallId = (String) args.arg1;
-                        addToConference(conferenceCallId, callIds);
-                    } finally {
-                        args.recycle();
-                    }
-                    break;
-                }
-                case MSG_SPLIT_FROM_CONFERENCE: {
+                case MSG_CONFERENCE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         String conferenceCallId = (String) args.arg1;
                         String callId = (String) args.arg2;
-                        splitFromConference(conferenceCallId, callId);
+                        conference(conferenceCallId, callId);
                     } finally {
                         args.recycle();
                     }
@@ -162,6 +150,9 @@
                     }
                     break;
                 }
+                case MSG_SPLIT_FROM_CONFERENCE:
+                    splitFromConference((String) msg.obj);
+                    break;
                 default:
                     break;
             }
@@ -245,19 +236,16 @@
         }
 
         @Override
-        public void addToConference(String conferenceCallId, List<String> callsToConference) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = conferenceCallId;
-            args.arg2 = callsToConference;
-            mMessageHandler.obtainMessage(MSG_ADD_TO_CONFERENCE, args).sendToTarget();
-        }
-
-        @Override
-        public void splitFromConference(String conferenceCallId, String callId) {
+        public void conference(String conferenceCallId, String callId) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = conferenceCallId;
             args.arg2 = callId;
-            mMessageHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, args).sendToTarget();
+            mMessageHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
+        }
+
+        @Override
+        public void splitFromConference(String callId) {
+            mMessageHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget();
         }
 
         @Override
@@ -424,24 +412,22 @@
     public abstract void onAudioStateChanged(String activeCallId, CallAudioState audioState);
 
     /**
-     * Adds the specified calls to the specified conference call.
+     * Conferences the specified call.
      *
      * @param conferenceCallId The unique ID of the conference call onto which the specified calls
      *         should be added.
-     * @param callIds The calls to add to the conference call.
+     * @param callId The call to conference.
      * @hide
      */
-    public abstract void addToConference(String conferenceCallId, List<String> callIds);
+    public abstract void conference(String conferenceCallId, String callId);
 
     /**
-     * Removes the specified call from the specified conference call. This is a no-op if the call
-     * is not already part of the conference call.
+     * Removes the specified call from a conference call.
      *
-     * @param conferenceCallId The conference call.
      * @param callId The call to remove from the conference call
      * @hide
      */
-    public abstract void splitFromConference(String conferenceCallId, String callId);
+    public abstract void splitFromConference(String callId);
 
     public void onPostDialContinue(String callId, boolean proceed) {}
     public void onPostDialWait(Connection conn, String remaining) {}
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
index 8c3ddad..0ba8161 100644
--- a/telecomm/java/android/telecomm/CallServiceAdapter.java
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -179,12 +179,12 @@
      * Indicates that the specified call can conference with any of the specified list of calls.
      *
      * @param callId The unique ID of the call.
-     * @param conferenceCapableCallIds The unique IDs of the calls which can be conferenced.
+     * @param canConference Specified whether or not the call can be conferenced.
      * @hide
      */
-    public void setCanConferenceWith(String callId, List<String> conferenceCapableCallIds) {
+    public void setCanConference(String callId, boolean canConference) {
         try {
-            mAdapter.setCanConferenceWith(callId, conferenceCapableCallIds);
+            mAdapter.setCanConference(callId, canConference);
         } catch (RemoteException ignored) {
         }
     }
@@ -193,13 +193,14 @@
      * Indicates whether or not the specified call is currently conferenced into the specified
      * conference call.
      *
-     * @param conferenceCallId The unique ID of the conference call.
      * @param callId The unique ID of the call being conferenced.
+     * @param conferenceCallId The unique ID of the conference call. Null if call is not
+     *         conferenced.
      * @hide
      */
-    public void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced) {
+    public void setIsConferenced(String callId, String conferenceCallId) {
         try {
-            mAdapter.setIsConferenced(conferenceCallId, callId, isConferenced);
+            mAdapter.setIsConferenced(callId, conferenceCallId);
         } catch (RemoteException ignored) {
         }
     }
@@ -236,4 +237,16 @@
         } catch (RemoteException e) {
         }
     }
+
+    /**
+     * Indicates that a new conference call has been created.
+     *
+     * @param callId The unique ID of the conference call.
+     */
+    public void addConferenceCall(String callId) {
+        try {
+            mAdapter.addConferenceCall(callId, null);
+        } catch (RemoteException ignored) {
+        }
+    }
 }
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 344814f..164eeff 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -19,7 +19,10 @@
 import android.net.Uri;
 import android.os.Bundle;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -35,6 +38,8 @@
         void onDisconnected(Connection c, int cause, String message);
         void onRequestingRingback(Connection c, boolean ringback);
         void onDestroyed(Connection c);
+        void onConferenceCapableChanged(Connection c, boolean isConferenceCapable);
+        void onParentConnectionChanged(Connection c, Connection parent);
     }
 
     public static class ListenerBase implements Listener {
@@ -65,6 +70,14 @@
         /** {@inheritDoc} */
         @Override
         public void onRequestingRingback(Connection c, boolean ringback) {}
+
+        /** ${inheritDoc} */
+        @Override
+        public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {}
+
+        /** ${inheritDoc} */
+        @Override
+        public void onParentConnectionChanged(Connection c, Connection parent) {}
     }
 
     public final class State {
@@ -79,10 +92,14 @@
     }
 
     private final Set<Listener> mListeners = new HashSet<>();
+    private final List<Connection> mChildConnections = new ArrayList<>();
+
     private int mState = State.NEW;
     private CallAudioState mCallAudioState;
     private Uri mHandle;
     private boolean mRequestingRingback = false;
+    private boolean mIsConferenceCapable = false;
+    private Connection mParentConnection;
 
     /**
      * Create a new Connection.
@@ -90,6 +107,13 @@
     protected Connection() {}
 
     /**
+     * The handle (e.g., phone number) to which this Connection is currently communicating.
+     *
+     * IMPORTANT: If an incoming connection has a phone number (or other handle) that the user
+     * is not supposed to be able to see (e.g. it is PRESENTATION_RESTRICTED), then a compliant
+     * ConnectionService implementation MUST NOT reveal this phone number and MUST return
+     * {@code null} from this method.
+     *
      * @return The handle (e.g., phone number) to which this Connection
      *         is currently communicating.
      */
@@ -176,6 +200,16 @@
     }
 
     /**
+     * Separates this Connection from a parent connection.
+     *
+     * @hide
+     */
+    public final void separate() {
+        Log.d(this, "separate");
+        onSeparate();
+    }
+
+    /**
      * Abort this Connection. The Connection will immediately transition to
      * the {@link State#DISCONNECTED} state, and send no notifications of this
      * or any other future events.
@@ -240,6 +274,14 @@
     }
 
     /**
+     * TODO(santoscordon): Needs updated documentation.
+     */
+    public final void conference() {
+        Log.d(this, "conference");
+        onConference();
+    }
+
+    /**
      * Inform this Connection that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
@@ -274,7 +316,7 @@
     }
 
     /**
-     * @return Whether this connection is requesting that the system play a ringback tone
+     * Returns whether this connection is requesting that the system play a ringback tone
      * on its behalf.
      */
     public boolean isRequestingRingback() {
@@ -282,6 +324,38 @@
     }
 
     /**
+     * Returns whether this connection is a conference connection (has child connections).
+     */
+    public boolean isConferenceConnection() {
+        return !mChildConnections.isEmpty();
+    }
+
+    public void setParentConnection(Connection parentConnection) {
+        Log.d(this, "parenting %s to %s", this, parentConnection);
+        if (mParentConnection != parentConnection) {
+            if (mParentConnection != null) {
+                mParentConnection.removeChild(this);
+            }
+            mParentConnection = parentConnection;
+            if (mParentConnection != null) {
+                mParentConnection.addChild(this);
+                // do something if the child connections goes down to ZERO.
+            }
+            for (Listener l : mListeners) {
+                l.onParentConnectionChanged(this, mParentConnection);
+            }
+        }
+    }
+
+    public Connection getParentConnection() {
+        return mParentConnection;
+    }
+
+    public List<Connection> getChildConnections() {
+        return mChildConnections;
+    }
+
+    /**
      * Sets the value of the {@link #getHandle()} property and notifies listeners.
      *
      * @param handle The new handle.
@@ -359,6 +433,32 @@
     }
 
     /**
+     * TODO(santoscordon): Needs documentation.
+     */
+    protected void setIsConferenceCapable(boolean isConferenceCapable) {
+        if (mIsConferenceCapable != isConferenceCapable) {
+            mIsConferenceCapable = isConferenceCapable;
+            for (Listener l : mListeners) {
+                l.onConferenceCapableChanged(this, mIsConferenceCapable);
+            }
+        }
+    }
+
+    /**
+     * TODO(santoscordon): Needs documentation.
+     */
+    protected void setDestroyed() {
+        // It is possible that onDestroy() will trigger the listener to remove itself which will
+        // result in a concurrent modification exception. To counteract this we make a copy of the
+        // listeners and iterate on that.
+        for (Listener l : new ArrayList<>(mListeners)) {
+            if (mListeners.contains(l)) {
+                l.onDestroyed(this);
+            }
+        }
+    }
+
+    /**
      * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
      * has a new value.
      *
@@ -418,6 +518,11 @@
     protected void onDisconnect() {}
 
     /**
+     * Notifies this Connection of a request to disconnect.
+     */
+    protected void onSeparate() {}
+
+    /**
      * Notifies this Connection of a request to abort.
      */
     protected void onAbort() {}
@@ -449,6 +554,28 @@
      */
     protected void onPostDialContinue(boolean proceed) {}
 
+    /**
+     * TODO(santoscordon): Needs documentation.
+     */
+    protected void onConference() {}
+
+    /**
+     * TODO(santoscordon): Needs documentation.
+     */
+    protected void onChildrenChanged(List<Connection> children) {}
+
+    private void addChild(Connection connection) {
+        Log.d(this, "adding child %s", connection);
+        mChildConnections.add(connection);
+        onChildrenChanged(mChildConnections);
+    }
+
+    private void removeChild(Connection connection) {
+        Log.d(this, "removing child %s", connection);
+        mChildConnections.remove(connection);
+        onChildrenChanged(mChildConnections);
+    }
+
     private void setState(int state) {
         Log.d(this, "setState: %s", stateToString(state));
         onSetState(state);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 59e977d..d974509 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -20,10 +20,15 @@
 import android.os.Bundle;
 import android.telephony.DisconnectCause;
 
+import android.os.SystemClock;
+
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * A {@link android.app.Service} that provides telephone connections to
@@ -32,7 +37,6 @@
 public abstract class ConnectionService extends CallService {
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
-
     private static final Connection NULL_CONNECTION = new Connection() {};
 
     // Mappings from Connections to IDs as understood by the current CallService implementation
@@ -99,6 +103,20 @@
             Log.d(this, "Adapter onRingback %b", ringback);
             getAdapter().setRequestingRingback(id, ringback);
         }
+
+        @Override
+        public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {
+            String id = mIdByConnection.get(c);
+            getAdapter().setCanConference(id, isConferenceCapable);
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void onParentConnectionChanged(Connection c, Connection parent) {
+            String id = mIdByConnection.get(c);
+            String parentId = parent == null ? null : mIdByConnection.get(parent);
+            getAdapter().setIsConferenced(id, parentId);
+        }
     };
 
     @Override
@@ -110,8 +128,7 @@
                     @Override
                     public void onResult(Uri handle, Subscription... result) {
                         boolean isCompatible = result.length > 0;
-                        Log.d(this, "adapter setIsCompatibleWith "
-                                + callInfo.getId() + " " + isCompatible);
+                        Log.d(this, "adapter setIsCompatibleWith ");
                         getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
                     }
 
@@ -135,7 +152,7 @@
                 new Response<ConnectionRequest, Connection>() {
                     @Override
                     public void onResult(ConnectionRequest request, Connection... result) {
-                        if (result.length != 1) {
+                        if (result != null && result.length != 1) {
                             Log.d(this, "adapter handleFailedOutgoingCall %s", callInfo);
                             getAdapter().handleFailedOutgoingCall(
                                     request,
@@ -145,10 +162,10 @@
                                 c.abort();
                             }
                         } else {
-                            addConnection(callInfo.getId(), result[0]);
                             Log.d(this, "adapter handleSuccessfulOutgoingCall %s",
                                     callInfo.getId());
                             getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+                            addConnection(callInfo.getId(), result[0]);
                         }
                     }
 
@@ -177,7 +194,7 @@
                 new Response<ConnectionRequest, Connection>() {
                     @Override
                     public void onResult(ConnectionRequest request, Connection... result) {
-                        if (result.length != 1) {
+                        if (result != null && result.length != 1) {
                             Log.d(this, "adapter handleFailedOutgoingCall %s", callId);
                             getAdapter().handleFailedOutgoingCall(
                                     request,
@@ -258,27 +275,43 @@
 
     /** @hide */
     @Override
-    public final void addToConference(String conferenceCallId, List<String> callIds) {
-        Log.d(this, "addToConference %s, %s", conferenceCallId, callIds);
+    public final void conference(final String conferenceCallId, String callId) {
+        Log.d(this, "conference %s, %s", conferenceCallId, callId);
 
-        List<Connection> connections = new LinkedList<>();
-        for (String id : callIds) {
-            Connection connection = findConnectionForAction(id, "addToConference");
-            if (connection == NULL_CONNECTION) {
-                Log.w(this, "Connection missing in conference request %s.", id);
-                return;
-            }
-            connections.add(connection);
+        Connection connection = findConnectionForAction(callId, "conference");
+        if (connection == NULL_CONNECTION) {
+            Log.w(this, "Connection missing in conference request %s.", callId);
+            return;
         }
 
-        // TODO(santoscordon): Find an existing conference call or create a new one. Then call
-        // conferenceWith on it.
+        onCreateConferenceConnection(conferenceCallId, connection,
+                new Response<String, Connection>() {
+                    /** ${inheritDoc} */
+                    @Override
+                    public void onResult(String ignored, Connection... result) {
+                        Log.d(this, "onCreateConference.Response %s", (Object[]) result);
+                        if (result != null && result.length == 1) {
+                            Connection conferenceConnection = result[0];
+                            if (!mIdByConnection.containsKey(conferenceConnection)) {
+                                Log.v(this, "sending new conference call %s", conferenceCallId);
+                                getAdapter().addConferenceCall(conferenceCallId);
+                                addConnection(conferenceCallId, conferenceConnection);
+                            }
+                        }
+                    }
+
+                    /** ${inheritDoc} */
+                    @Override
+                    public void onError(String request, int code, String reason) {
+                        // no-op
+                    }
+                });
     }
 
     /** @hide */
     @Override
-    public final void splitFromConference(String conferenceCallId, String callId) {
-        Log.d(this, "splitFromConference(%s, %s)", conferenceCallId, callId);
+    public final void splitFromConference(String callId) {
+        Log.d(this, "splitFromConference(%s)", callId);
 
         Connection connection = findConnectionForAction(callId, "splitFromConference");
         if (connection == NULL_CONNECTION) {
@@ -309,6 +342,13 @@
     }
 
     /**
+     * Returns all connections currently associated with this connection service.
+     */
+    public Collection<Connection> getAllConnections() {
+        return mConnectionById.values();
+    }
+
+    /**
      * Find a set of Subscriptions matching a given handle (e.g. phone number).
      *
      * @param handle A handle (e.g. phone number) with which to connect.
@@ -329,8 +369,28 @@
             Response<ConnectionRequest, Connection> callback) {}
 
     /**
+     * Returns a new or existing conference connection when the the user elects to convert the
+     * specified connection into a conference call. The specified connection can be any connection
+     * which had previously specified itself as conference-capable including both simple connections
+     * and connections previously returned from this method.
+     *
+     * @param connection The connection from which the user opted to start a conference call.
+     * @param token The token to be passed into the response callback.
+     * @param callback The callback for providing the potentially-new conference connection.
+     */
+    public void onCreateConferenceConnection(
+            String token,
+            Connection connection,
+            Response<String, Connection> callback) {}
+
+    /**
      * Create a Connection to match an incoming connection notification.
      *
+     * IMPORTANT: If the incoming connection has a phone number (or other handle) that the user
+     * is not supposed to be able to see (e.g. it is PRESENTATION_RESTRICTED), then a compliant
+     * ConnectionService implementation MUST NOT reveal this phone number as part of the Intent
+     * it sends to notify Telecomm of an incoming connection.
+     *
      * @param request Data encapsulating details of the desired Connection.
      * @param callback A callback for providing the result.
      */
@@ -338,6 +398,20 @@
             ConnectionRequest request,
             Response<ConnectionRequest, Connection> callback) {}
 
+    /**
+     * Notifies that a connection has been added to this connection service and sent to Telecomm.
+     *
+     * @param connection The connection which was added.
+     */
+    public void onConnectionAdded(Connection connection) {}
+
+    /**
+     * Notified that a connection has been removed from this connection service.
+     *
+     * @param connection The connection which was removed.
+     */
+    public void onConnectionRemoved(Connection connection) {}
+
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
         if (number == null) {
@@ -387,12 +461,14 @@
         mConnectionById.put(callId, connection);
         mIdByConnection.put(connection, callId);
         connection.addConnectionListener(mConnectionListener);
+        onConnectionAdded(connection);
     }
 
     private void removeConnection(Connection connection) {
         connection.removeConnectionListener(mConnectionListener);
         mConnectionById.remove(mIdByConnection.get(connection));
         mIdByConnection.remove(connection);
+        onConnectionRemoved(connection);
     }
 
     private Connection findConnectionForAction(String callId, String action) {
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 0bef419..ce52d19 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -59,10 +59,12 @@
      * is ported over.
      *
      * @param callId The identifier of the call to reject.
+     * @param rejectWithMessage Whether to reject with a text message.
+     * @param textMessage An optional text message with which to respond.
      */
-    public void rejectCall(String callId) {
+    public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
         try {
-            mAdapter.rejectCall(callId);
+            mAdapter.rejectCall(callId, rejectWithMessage, textMessage);
         } catch (RemoteException e) {
         }
     }
@@ -199,15 +201,14 @@
     }
 
     /**
-     * Instructs Telecomm to conference the specified calls together.
+     * Instructs Telecomm to conference the specified call.
      *
      * @param callId The unique ID of the call.
-     * @param callIdToConference The unique ID of the call to conference with.
      * @hide
      */
-    void conferenceWith(String callId, String callIdToConference) {
+    public void conference(String callId) {
         try {
-            mAdapter.conferenceWith(callId, callIdToConference);
+            mAdapter.conference(callId);
         } catch (RemoteException ignored) {
         }
     }
@@ -219,7 +220,7 @@
      * @param callId The unique ID of the call.
      * @hide
      */
-    void splitFromConference(String callId) {
+    public void splitFromConference(String callId) {
         try {
             mAdapter.splitFromConference(callId);
         } catch (RemoteException ignored) {
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
index b531ccd..66974f9 100644
--- a/telecomm/java/android/telecomm/InCallCall.java
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -33,13 +33,13 @@
     private final CallState mState;
     private final int mDisconnectCauseCode;
     private final String mDisconnectCauseMsg;
+    private final List<String> mCannedSmsResponses;
     private final int mCapabilities;
     private final long mConnectTimeMillis;
     private final Uri mHandle;
     private final GatewayInfo mGatewayInfo;
     private final CallServiceDescriptor mCurrentCallServiceDescriptor;
     private final CallServiceDescriptor mHandoffCallServiceDescriptor;
-    private final List<String> mConferenceCapableCallIds;
     private final String mParentCallId;
     private final List<String> mChildCallIds;
 
@@ -50,15 +50,16 @@
             CallState state,
             int disconnectCauseCode,
             String disconnectCauseMsg,
+            List<String> cannedSmsResponses,
             int capabilities,
             long connectTimeMillis,
             Uri handle,
             GatewayInfo gatewayInfo,
             CallServiceDescriptor descriptor,
             CallServiceDescriptor handoffDescriptor) {
-        this(id, state, disconnectCauseCode, disconnectCauseMsg, capabilities, connectTimeMillis,
-                handle, gatewayInfo, descriptor, handoffDescriptor, Collections.EMPTY_LIST, null,
-                Collections.EMPTY_LIST);
+        this(id, state, disconnectCauseCode, disconnectCauseMsg, cannedSmsResponses,
+                capabilities, connectTimeMillis, handle, gatewayInfo, descriptor, handoffDescriptor,
+                null, Collections.EMPTY_LIST);
     }
 
     /** @hide */
@@ -67,26 +68,26 @@
             CallState state,
             int disconnectCauseCode,
             String disconnectCauseMsg,
+            List<String> cannedSmsResponses,
             int capabilities,
             long connectTimeMillis,
             Uri handle,
             GatewayInfo gatewayInfo,
             CallServiceDescriptor descriptor,
             CallServiceDescriptor handoffDescriptor,
-            List<String> conferenceCapableCallIds,
             String parentCallId,
             List<String> childCallIds) {
         mId = id;
         mState = state;
         mDisconnectCauseCode = disconnectCauseCode;
         mDisconnectCauseMsg = disconnectCauseMsg;
+        mCannedSmsResponses = cannedSmsResponses;
         mCapabilities = capabilities;
         mConnectTimeMillis = connectTimeMillis;
         mHandle = handle;
         mGatewayInfo = gatewayInfo;
         mCurrentCallServiceDescriptor = descriptor;
         mHandoffCallServiceDescriptor = handoffDescriptor;
-        mConferenceCapableCallIds = conferenceCapableCallIds;
         mParentCallId = parentCallId;
         mChildCallIds = childCallIds;
     }
@@ -117,6 +118,13 @@
         return mDisconnectCauseMsg;
     }
 
+    /**
+     * The set of possible text message responses when this call is incoming.
+     */
+    public List<String> getCannedSmsResponses() {
+        return mCannedSmsResponses;
+    }
+
     // Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
     public int getCapabilities() {
         return mCapabilities;
@@ -151,14 +159,6 @@
     }
 
     /**
-     * The calls with which this call can conference.
-     * @hide
-     */
-    public List<String> getConferenceCapableCallIds() {
-        return mConferenceCapableCallIds;
-    }
-
-    /**
      * The conference call to which this call is conferenced. Null if not conferenced.
      * @hide
      */
@@ -180,25 +180,25 @@
             new Parcelable.Creator<InCallCall> () {
         @Override
         public InCallCall createFromParcel(Parcel source) {
+            ClassLoader classLoader = InCallCall.class.getClassLoader();
             String id = source.readString();
             CallState state = CallState.valueOf(source.readString());
             int disconnectCauseCode = source.readInt();
             String disconnectCauseMsg = source.readString();
+            List<String> cannedSmsResponses = new ArrayList<>();
+            source.readList(cannedSmsResponses, classLoader);
             int capabilities = source.readInt();
             long connectTimeMillis = source.readLong();
-            ClassLoader classLoader = InCallCall.class.getClassLoader();
             Uri handle = source.readParcelable(classLoader);
             GatewayInfo gatewayInfo = source.readParcelable(classLoader);
             CallServiceDescriptor descriptor = source.readParcelable(classLoader);
             CallServiceDescriptor handoffDescriptor = source.readParcelable(classLoader);
-            List<String> conferenceCapableCallIds = new ArrayList<>();
-            source.readList(conferenceCapableCallIds, classLoader);
             String parentCallId = source.readString();
             List<String> childCallIds = new ArrayList<>();
             source.readList(childCallIds, classLoader);
-            return new InCallCall(id, state, disconnectCauseCode, disconnectCauseMsg, capabilities,
-                    connectTimeMillis, handle, gatewayInfo, descriptor, handoffDescriptor,
-                    conferenceCapableCallIds, parentCallId, childCallIds);
+            return new InCallCall(id, state, disconnectCauseCode, disconnectCauseMsg,
+                    cannedSmsResponses, capabilities, connectTimeMillis, handle, gatewayInfo,
+                    descriptor, handoffDescriptor, parentCallId, childCallIds);
         }
 
         @Override
@@ -220,14 +220,19 @@
         destination.writeString(mState.name());
         destination.writeInt(mDisconnectCauseCode);
         destination.writeString(mDisconnectCauseMsg);
+        destination.writeList(mCannedSmsResponses);
         destination.writeInt(mCapabilities);
         destination.writeLong(mConnectTimeMillis);
         destination.writeParcelable(mHandle, 0);
         destination.writeParcelable(mGatewayInfo, 0);
         destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
         destination.writeParcelable(mHandoffCallServiceDescriptor, 0);
-        destination.writeList(mConferenceCapableCallIds);
         destination.writeString(mParentCallId);
         destination.writeList(mChildCallIds);
     }
+
+    @Override
+    public String toString() {
+        return String.format("[%s, parent:%s, children:%s]", mId, mParentCallId, mChildCallIds);
+    }
 }
diff --git a/telecomm/java/android/telecomm/PhoneApplication.java b/telecomm/java/android/telecomm/PhoneApplication.java
new file mode 100644
index 0000000..1da54e0
--- /dev/null
+++ b/telecomm/java/android/telecomm/PhoneApplication.java
@@ -0,0 +1,183 @@
+package android.telecomm;
+
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telecomm.ITelecommService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class for managing the primary phone application that will receive incoming calls, and be allowed
+ * to make emergency outgoing calls.
+ *
+ * @hide
+ */
+public class PhoneApplication {
+    private static final String TAG = PhoneApplication.class.getSimpleName();
+    private static final String TELECOMM_SERVICE_NAME = "telecomm";
+
+    /**
+     * Sets the specified package name as the default phone application. The caller of this method
+     * needs to have permission to write to secure settings.
+     *
+     * @hide
+     * */
+    @SystemApi
+    public static void setDefaultPhoneApplication(String packageName, Context context) {
+        // Get old package name
+        String oldPackageName = Settings.Secure.getString(context.getContentResolver(),
+                Settings.Secure.PHONE_DEFAULT_APPLICATION);
+
+        if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
+            // No change
+            return;
+        }
+
+        // Only make the change if the new package belongs to a valid phone application
+        List<ComponentName> componentNames = getInstalledPhoneApplications(context);
+        ComponentName foundComponent = null;
+        for (ComponentName componentName : componentNames) {
+            if (TextUtils.equals(componentName.getPackageName(), packageName)) {
+                foundComponent = componentName;
+                break;
+            }
+        }
+
+        if (foundComponent != null) {
+            // Update the secure setting.
+            Settings.Secure.putString(context.getContentResolver(),
+                    Settings.Secure.PHONE_DEFAULT_APPLICATION, foundComponent.getPackageName());
+        }
+    }
+
+    /**
+     * Returns the installed phone application that will be used to receive incoming calls, and is
+     * allowed to make emergency calls.
+     *
+     * The application will be returned in order of preference:
+     * 1) User selected phone application (if still installed)
+     * 2) Pre-installed system dialer (if not disabled)
+     * 3) Null
+     *
+     * @hide
+     * */
+    @SystemApi
+    public static ComponentName getDefaultPhoneApplication(Context context) {
+        String defaultPackageName = Settings.Secure.getString(context.getContentResolver(),
+                Settings.Secure.PHONE_DEFAULT_APPLICATION);
+
+        final List<ComponentName> componentNames = getInstalledPhoneApplications(context);
+        if (!TextUtils.isEmpty(defaultPackageName)) {
+            for (ComponentName componentName : componentNames) {
+                if (TextUtils.equals(componentName.getPackageName(), defaultPackageName)) {
+                    return componentName;
+                }
+            }
+        }
+
+        // No user-set dialer found, fallback to system dialer
+        ComponentName systemDialer = null;
+        try {
+            systemDialer = getTelecommService().getSystemPhoneApplication();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#getSystemPhoneApplication", e);
+            return null;
+        }
+
+        if (systemDialer == null) {
+            // No system dialer configured at build time
+            return null;
+        }
+
+        // Verify that the system dialer has not been disabled.
+        return getComponentName(componentNames, systemDialer.getPackageName());
+    }
+
+    /**
+     * Returns a list of installed and available phone applications.
+     *
+     * In order to appear in the list, a phone application must implement an intent-filter with
+     * the DIAL intent for the following schemes:
+     *
+     * 1) Empty scheme
+     * 2) tel Uri scheme
+     *
+     * @hide
+     **/
+    @SystemApi
+    public static List<ComponentName> getInstalledPhoneApplications(Context context) {
+        PackageManager packageManager = context.getPackageManager();
+
+        // Get the list of apps registered for the DIAL intent with empty scheme
+        Intent intent = new Intent(Intent.ACTION_DIAL);
+        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
+
+        List<ComponentName> componentNames = new ArrayList<ComponentName> ();
+
+        for (ResolveInfo resolveInfo : resolveInfoList) {
+            final ActivityInfo activityInfo = resolveInfo.activityInfo;
+            if (activityInfo == null) {
+                continue;
+            }
+            final ComponentName componentName =
+                    new ComponentName(activityInfo.packageName, activityInfo.name);
+            componentNames.add(componentName);
+        }
+
+        // TODO: Filter for apps that don't handle DIAL intent with tel scheme
+        return componentNames;
+    }
+
+    /**
+     * Returns the {@link ComponentName} for the installed phone application for a given package
+     * name.
+     *
+     * @param context A valid context.
+     * @param packageName to retrieve the {@link ComponentName} for.
+     *
+     * @return The {@link ComponentName} for the installed phone application corresponding to the
+     * package name, or null if none is found.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static ComponentName getPhoneApplicationForPackageName(Context context,
+            String packageName) {
+        return getComponentName(getInstalledPhoneApplications(context), packageName);
+    }
+
+    /**
+     * Returns the component from a list of application components that corresponds to the package
+     * name.
+     *
+     * @param componentNames A list of component names
+     * @param packageName The package name to look for
+     * @return The {@link ComponentName} that matches the provided packageName, or null if not
+     *         found.
+     */
+    private static ComponentName getComponentName(List<ComponentName> componentNames,
+            String packageName) {
+        for (ComponentName componentName : componentNames) {
+            if (TextUtils.equals(packageName, componentName.getPackageName())) {
+                return componentName;
+            }
+        }
+        return null;
+    }
+
+    private static ITelecommService getTelecommService() {
+        return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
+    }
+}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index 8300c92..0952097 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -16,6 +16,7 @@
 
 package android.telecomm;
 
+import android.content.Intent;
 import android.os.Bundle;
 import android.telephony.TelephonyManager;
 
@@ -55,6 +56,28 @@
     public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName();
 
     /**
+     * Activity action: Ask the user to change the default phone application. This will show a
+     * dialog that asks the user whether they want to replace the current default phone application
+     * with the one defined in {@link #EXTRA_PACKAGE_NAME}.
+     */
+    public static final String ACTION_CHANGE_DEFAULT_PHONE =
+            "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE";
+
+    /**
+     * The PackageName string passed in as an extra for {@link #ACTION_CHANGE_DEFAULT_PHONE}.
+     *
+     * @see #ACTION_CHANGE_DEFAULT_PHONE
+     */
+    public static final String EXTRA_PACKAGE_NAME = "package";
+
+    /**
+     * Optional extra for {@link Intent#ACTION_CALL} containing a boolean that determines whether
+     * the speakerphone should be automatically turned on for an outgoing call.
+     */
+    public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE =
+            "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+
+    /**
      * Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
      * describes the call service to use for the incoming call.
      */
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
new file mode 100644
index 0000000..a97e7e4
--- /dev/null
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.content.Context;
+
+import com.android.internal.telecomm.ITelecommService;
+
+/**
+ * Provides access to Telecomm-related functionality.
+ */
+public class TelecommManager {
+    private static final String TAG = "TelecommManager";
+
+    private final Context mContext;
+    private final ITelecommService mService;
+
+    /** @hide */
+    public TelecommManager(Context context, ITelecommService service) {
+        Context appContext = context.getApplicationContext();
+        if (appContext != null) {
+            mContext = appContext;
+        } else {
+            mContext = context;
+        }
+
+        mService = service;
+    }
+
+    /** {@hide} */
+    public static TelecommManager from(Context context) {
+        return (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
+    }
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallService.aidl b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
index 9139aa6..827f331 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
@@ -56,9 +56,9 @@
 
     void stopDtmfTone(String callId);
 
-    void addToConference(String conferenceCallId, in List<String> callIds);
+    void conference(String conferenceCallId, String callId);
 
-    void splitFromConference(String conferenceCallId, String callId);
+    void splitFromConference(String callId);
 
     void onPostDialContinue(String callId, boolean proceed);
 }
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
index b380293..6e176eb 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
@@ -47,9 +47,11 @@
 
     void setRequestingRingback(String callId, boolean ringing);
 
-    void setCanConferenceWith(String callId, in List<String> conferenceCapableCallIds);
+    void setCanConference(String callId, boolean canConference);
 
-    void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced);
+    void setIsConferenced(String callId, String conferenceCallId);
+
+    void addConferenceCall(String callId, in CallInfo callInfo);
 
     void removeCall(String callId);
 
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
index f144043..b66995a 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -28,7 +28,7 @@
 oneway interface IInCallAdapter {
     void answerCall(String callId);
 
-    void rejectCall(String callId);
+    void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
 
     void disconnectCall(String callId);
 
@@ -48,7 +48,7 @@
 
     void handoffCall(String callId);
 
-    void conferenceWith(String callId, String callIdToConference);
+    void conference(String callId);
 
     void splitFromConference(String callId);
 }
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 0e94ffb..638b86a 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -16,6 +16,8 @@
 
 package com.android.internal.telecomm;
 
+import android.content.ComponentName;
+
 /**
  * Interface used to interact with Telecomm. Mostly this is used by TelephonyManager for passing
  * commands that were previously handled by ITelephony.
@@ -38,4 +40,9 @@
      * @param showDialpad if true, make the dialpad visible initially.
      */
     void showCallScreen(boolean showDialpad);
+
+    /**
+     * Returns the component name of the phone application installed on the system partition.
+     */
+    ComponentName getSystemPhoneApplication();
 }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ed7f6b8..b935d2a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -36,6 +36,7 @@
 import android.telephony.Rlog;
 import android.util.SparseIntArray;
 
+import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
@@ -166,7 +167,9 @@
         // TODO: We don't check for SecurityException here (requires
         // CALL_PRIVILEGED permission).
         if (scheme.equals("voicemail")) {
-            return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
+            long subId = intent.getLongExtra(SUBSCRIPTION_KEY,
+                    SubscriptionManager.getDefaultVoiceSubId());
+            return TelephonyManager.getDefault().getCompleteVoiceMailNumber(subId);
         }
 
         if (context == null) {
@@ -1144,7 +1147,7 @@
      * @return A locally acceptable formatting of the input, or the raw input if
      *  formatting rules aren't known for the number
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static String formatNumber(String source) {
         SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1162,7 +1165,7 @@
      * @return The phone number formatted with the given formatting type.
      *
      * @hide
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static String formatNumber(String source, int defaultFormattingType) {
         SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1177,7 +1180,7 @@
      * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
      * rules are not known for the given locale
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static int getFormatTypeForLocale(Locale locale) {
         String country = locale.getCountry();
@@ -1193,7 +1196,7 @@
      * @param defaultFormattingType The default formatting rules to apply if the number does
      * not begin with +[country_code]
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static void formatNumber(Editable text, int defaultFormattingType) {
         int formatType = defaultFormattingType;
@@ -1241,7 +1244,7 @@
      *
      * @param text the number to be formatted, will be modified with the formatting
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static void formatNanpNumber(Editable text) {
         int length = text.length();
@@ -1356,7 +1359,7 @@
      * @param text the number to be formatted, will be modified with
      * the formatting
      *
-     * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+     * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
     public static void formatJapaneseNumber(Editable text) {
         JapanesePhoneNumberFormatter.format(text);
@@ -1560,9 +1563,23 @@
      *         listed in the RIL / SIM, otherwise return false.
      */
     public static boolean isEmergencyNumber(String number) {
+        return isEmergencyNumber(getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks a given number against the list of
+     * emergency numbers provided by the RIL and SIM card.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @return true if the number is in the list of emergency numbers
+     *         listed in the RIL / SIM, otherwise return false.
+     * @hide
+     */
+    public static boolean isEmergencyNumber(long subId, String number) {
         // Return true only if the specified number *exactly* matches
         // one of the emergency numbers listed by the RIL / SIM.
-        return isEmergencyNumberInternal(number, true /* useExactMatch */);
+        return isEmergencyNumberInternal(subId, number, true /* useExactMatch */);
     }
 
     /**
@@ -1586,9 +1603,33 @@
      * @hide
      */
     public static boolean isPotentialEmergencyNumber(String number) {
+        return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks if given number might *potentially* result in
+     * a call to an emergency service on the current network.
+     *
+     * Specifically, this method will return true if the specified number
+     * is an emergency number according to the list managed by the RIL or
+     * SIM, *or* if the specified number simply starts with the same
+     * digits as any of the emergency numbers listed in the RIL / SIM.
+     *
+     * This method is intended for internal use by the phone app when
+     * deciding whether to allow ACTION_CALL intents from 3rd party apps
+     * (where we're required to *not* allow emergency calls to be placed.)
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @return true if the number is in the list of emergency numbers
+     *         listed in the RIL / SIM, *or* if the number starts with the
+     *         same digits as any of those emergency numbers.
+     * @hide
+     */
+    public static boolean isPotentialEmergencyNumber(long subId, String number) {
         // Check against the emergency numbers listed by the RIL / SIM,
         // and *don't* require an exact match.
-        return isEmergencyNumberInternal(number, false /* useExactMatch */);
+        return isEmergencyNumberInternal(subId, number, false /* useExactMatch */);
     }
 
     /**
@@ -1611,7 +1652,32 @@
      *         listed in the RIL / sim, otherwise return false.
      */
     private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
-        return isEmergencyNumberInternal(number, null, useExactMatch);
+        return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch);
+    }
+
+    /**
+     * Helper function for isEmergencyNumber(String) and
+     * isPotentialEmergencyNumber(String).
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     *
+     * @param useExactMatch if true, consider a number to be an emergency
+     *           number only if it *exactly* matches a number listed in
+     *           the RIL / SIM.  If false, a number is considered to be an
+     *           emergency number if it simply starts with the same digits
+     *           as any of the emergency numbers listed in the RIL / SIM.
+     *           (Setting useExactMatch to false allows you to identify
+     *           number that could *potentially* result in emergency calls
+     *           since many networks will actually ignore trailing digits
+     *           after a valid emergency number.)
+     *
+     * @return true if the number is in the list of emergency numbers
+     *         listed in the RIL / sim, otherwise return false.
+     */
+    private static boolean isEmergencyNumberInternal(long subId, String number,
+            boolean useExactMatch) {
+        return isEmergencyNumberInternal(subId, number, null, useExactMatch);
     }
 
     /**
@@ -1625,7 +1691,21 @@
      * @hide
      */
     public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
-        return isEmergencyNumberInternal(number,
+            return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+    }
+
+    /**
+     * Checks if a given number is an emergency number for a specific country.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @return if the number is an emergency number for the specific country, then return true,
+     * otherwise false
+     * @hide
+     */
+    public static boolean isEmergencyNumber(long subId, String number, String defaultCountryIso) {
+        return isEmergencyNumberInternal(subId, number,
                                          defaultCountryIso,
                                          true /* useExactMatch */);
     }
@@ -1652,7 +1732,33 @@
      * @hide
      */
     public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
-        return isEmergencyNumberInternal(number,
+        return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+    }
+
+    /**
+     * Checks if a given number might *potentially* result in a call to an
+     * emergency service, for a specific country.
+     *
+     * Specifically, this method will return true if the specified number
+     * is an emergency number in the specified country, *or* if the number
+     * simply starts with the same digits as any emergency number for that
+     * country.
+     *
+     * This method is intended for internal use by the phone app when
+     * deciding whether to allow ACTION_CALL intents from 3rd party apps
+     * (where we're required to *not* allow emergency calls to be placed.)
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @return true if the number is an emergency number for the specific
+     *         country, *or* if the number starts with the same digits as
+     *         any of those emergency numbers.
+     * @hide
+     */
+    public static boolean isPotentialEmergencyNumber(long subId, String number,
+            String defaultCountryIso) {
+        return isEmergencyNumberInternal(subId, number,
                                          defaultCountryIso,
                                          false /* useExactMatch */);
     }
@@ -1674,6 +1780,29 @@
     private static boolean isEmergencyNumberInternal(String number,
                                                      String defaultCountryIso,
                                                      boolean useExactMatch) {
+        return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso,
+                useExactMatch);
+    }
+
+    /**
+     * Helper function for isEmergencyNumber(String, String) and
+     * isPotentialEmergencyNumber(String, String).
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param defaultCountryIso the specific country which the number should be checked against
+     * @param useExactMatch if true, consider a number to be an emergency
+     *           number only if it *exactly* matches a number listed in
+     *           the RIL / SIM.  If false, a number is considered to be an
+     *           emergency number if it simply starts with the same digits
+     *           as any of the emergency numbers listed in the RIL / SIM.
+     *
+     * @return true if the number is an emergency number for the specified country.
+     * @hide
+     */
+    private static boolean isEmergencyNumberInternal(long subId, String number,
+                                                     String defaultCountryIso,
+                                                     boolean useExactMatch) {
         // If the number passed in is null, just return false:
         if (number == null) return false;
 
@@ -1692,9 +1821,14 @@
         // to the list.
         number = extractNetworkPortionAlt(number);
 
+        String numbers = "";
+        int slotId = SubscriptionManager.getSlotId(subId);
         // retrieve the list of emergency numbers
         // check read-write ecclist property first
-        String numbers = SystemProperties.get("ril.ecclist");
+        String ecclist = (slotId == 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+
+        numbers = SystemProperties.get(ecclist);
+
         if (TextUtils.isEmpty(numbers)) {
             // then read-only ecclist property since old RIL only uses this
             numbers = SystemProperties.get("ro.ril.ecclist");
@@ -1742,15 +1876,29 @@
 
     /**
      * Checks if a given number is an emergency number for the country that the user is in.
-     * @param context the specific context which the number should be checked against
-     * @param number the number to look up.
      *
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
      * @return true if the specified number is an emergency number for the country the user
      * is currently in.
      */
     public static boolean isLocalEmergencyNumber(Context context, String number) {
-        return isLocalEmergencyNumberInternal(context,
-                                              number,
+        return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks if a given number is an emergency number for the country that the user is in.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
+     * @return true if the specified number is an emergency number for the country the user
+     * is currently in.
+     * @hide
+     */
+    public static boolean isLocalEmergencyNumber(Context context, long subId, String number) {
+        return isLocalEmergencyNumberInternal(subId, number,
+                                              context,
                                               true /* useExactMatch */);
     }
 
@@ -1767,9 +1915,9 @@
      * This method is intended for internal use by the phone app when
      * deciding whether to allow ACTION_CALL intents from 3rd party apps
      * (where we're required to *not* allow emergency calls to be placed.)
-     * @param context the specific context which the number should be checked against
-     * @param number the number to look up.
      *
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
      * @return true if the specified number is an emergency number for a local country, based on the
      *              CountryDetector.
      *
@@ -1777,16 +1925,44 @@
      * @hide
      */
     public static boolean isPotentialLocalEmergencyNumber(Context context, String number) {
-        return isLocalEmergencyNumberInternal(context,
-                                              number,
+        return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+    }
+
+    /**
+     * Checks if a given number might *potentially* result in a call to an
+     * emergency service, for the country that the user is in. The current
+     * country is determined using the CountryDetector.
+     *
+     * Specifically, this method will return true if the specified number
+     * is an emergency number in the current country, *or* if the number
+     * simply starts with the same digits as any emergency number for the
+     * current country.
+     *
+     * This method is intended for internal use by the phone app when
+     * deciding whether to allow ACTION_CALL intents from 3rd party apps
+     * (where we're required to *not* allow emergency calls to be placed.)
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
+     * @return true if the specified number is an emergency number for a local country, based on the
+     *              CountryDetector.
+     *
+     * @hide
+     */
+    public static boolean isPotentialLocalEmergencyNumber(Context context, long subId,
+            String number) {
+        return isLocalEmergencyNumberInternal(subId, number,
+                                              context,
                                               false /* useExactMatch */);
     }
 
     /**
      * Helper function for isLocalEmergencyNumber() and
      * isPotentialLocalEmergencyNumber().
-     * @param context the specific context which the number should be checked against
+     *
      * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
      * @param useExactMatch if true, consider a number to be an emergency
      *           number only if it *exactly* matches a number listed in
      *           the RIL / SIM.  If false, a number is considered to be an
@@ -1797,9 +1973,34 @@
      *              local country, based on the CountryDetector.
      *
      * @see android.location.CountryDetector
+     * @hide
      */
-    private static boolean isLocalEmergencyNumberInternal(Context context,
-                                                          String number,
+    private static boolean isLocalEmergencyNumberInternal(String number,
+                                                          Context context,
+                                                          boolean useExactMatch) {
+        return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context,
+                useExactMatch);
+    }
+
+    /**
+     * Helper function for isLocalEmergencyNumber() and
+     * isPotentialLocalEmergencyNumber().
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @param context the specific context which the number should be checked against
+     * @param useExactMatch if true, consider a number to be an emergency
+     *           number only if it *exactly* matches a number listed in
+     *           the RIL / SIM.  If false, a number is considered to be an
+     *           emergency number if it simply starts with the same digits
+     *           as any of the emergency numbers listed in the RIL / SIM.
+     *
+     * @return true if the specified number is an emergency number for a
+     *              local country, based on the CountryDetector.
+     * @hide
+     */
+    private static boolean isLocalEmergencyNumberInternal(long subId, String number,
+                                                          Context context,
                                                           boolean useExactMatch) {
         String countryIso;
         CountryDetector detector = (CountryDetector) context.getSystemService(
@@ -1812,7 +2013,7 @@
             Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
                     + countryIso);
         }
-        return isEmergencyNumberInternal(number, countryIso, useExactMatch);
+        return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
     }
 
     /**
@@ -1826,10 +2027,26 @@
      * to read the VM number.
      */
     public static boolean isVoiceMailNumber(String number) {
+        return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+    }
+
+    /**
+     * isVoiceMailNumber: checks a given number against the voicemail
+     *   number provided by the RIL and SIM card. The caller must have
+     *   the READ_PHONE_STATE credential.
+     *
+     * @param subId the subscription id of the SIM.
+     * @param number the number to look up.
+     * @return true if the number is in the list of voicemail. False
+     * otherwise, including if the caller does not have the permission
+     * to read the VM number.
+     * @hide
+     */
+    public static boolean isVoiceMailNumber(long subId, String number) {
         String vmNumber;
 
         try {
-            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(subId);
         } catch (SecurityException ex) {
             return false;
         }
@@ -2561,5 +2778,11 @@
         return true;
     }
 
+    /**
+     * Returns Default voice subscription Id.
+     */
+    private static long getDefaultVoiceSubId() {
+        return SubscriptionManager.getDefaultVoiceSubId();
+    }
     //==== End of utility methods used only in compareStrictly() =====
 }
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 59ec6f5..c8c3063 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,11 +20,13 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
 import android.telephony.CellLocation;
 import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
 import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 
@@ -48,6 +50,7 @@
  * appropriate LISTEN_ flags.
  */
 public class PhoneStateListener {
+    private static final String TAG = "PhoneStateListener";
 
     /**
      * Stop listening for updates.
@@ -200,18 +203,42 @@
      */
     public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO           = 0x00002000;
 
+    /**
+     * Listen for changes to LTE network state
+     *
+     * @see #onLteNetworkStateChanged
+     * @hide
+     */
+    public static final int LISTEN_VOLTE_STATE                              = 0x00004000;
+
+     /*
+     * Subscription used to listen to the phone state changes
+     * @hide
+     */
+    /** @hide */
+    protected long mSubId = 0;
+
     private final Handler mHandler;
 
     public PhoneStateListener() {
-        this(Looper.myLooper());
+        this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
+    }
+
+    /**
+     * @hide
+     */
+    public PhoneStateListener(long subId) {
+        this(subId, Looper.myLooper());
     }
 
     /** @hide */
-    public PhoneStateListener(Looper looper) {
+    public PhoneStateListener(long subId, Looper looper) {
+        Rlog.d(TAG, "ctor: subId=" + subId + " looper=" + looper);
+        mSubId = subId;
         mHandler = new Handler(looper) {
             public void handleMessage(Message msg) {
-                //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
-                // + " msg=" + msg);
+                Rlog.d(TAG, "mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
+                 + " msg=" + msg);
                 switch (msg.what) {
                     case LISTEN_SERVICE_STATE:
                         PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
@@ -258,6 +285,9 @@
                         PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
                                 (DataConnectionRealTimeInfo)msg.obj);
                         break;
+                    case LISTEN_VOLTE_STATE:
+                        PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
+                        break;
                 }
             }
         };
@@ -417,6 +447,15 @@
     }
 
     /**
+     * Callback invoked when the service state of LTE network
+     * related to the VoLTE service has changed.
+     * @param stateInfo is the current LTE network information
+     * @hide
+     */
+    public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) {
+    }
+
+    /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
      */
@@ -484,5 +523,9 @@
             Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0,
                     dcRtInfo).sendToTarget();
         }
+
+        public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
+            Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
+        }
     };
 }
diff --git a/telephony/java/android/telephony/SubInfoRecord.aidl b/telephony/java/android/telephony/SubInfoRecord.aidl
new file mode 100755
index 0000000..a2de676
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.aidl
@@ -0,0 +1,19 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable SubInfoRecord;
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
new file mode 100644
index 0000000..670def7
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -0,0 +1,108 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  A parcelable holder class of byte[] for ISms aidl implementation
+ *  @hide
+ */
+
+public class SubInfoRecord implements Parcelable {
+
+    public long mSubId;
+    public String mIccId;
+    public int mSlotId;
+    public String mDisplayName;
+    public int mNameSource;
+    public int mColor;
+    public String mNumber;
+    public int mDispalyNumberFormat;
+    public int mDataRoaming;
+    public int[] mSimIconRes;
+
+    public SubInfoRecord() {
+        this.mSubId = -1;
+        this.mIccId = "";
+        this.mSlotId = -1;
+        this.mDisplayName = "";
+        this.mNameSource = 0;
+        this.mColor = 0;
+        this.mNumber = "";
+        this.mDispalyNumberFormat = 0;
+        this.mDataRoaming = 0;
+        this.mSimIconRes = new int[2];
+    }
+
+
+    public SubInfoRecord(long subId, String iccId, int slotId, String displayname, int nameSource,
+            int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
+        this.mSubId = subId;
+        this.mIccId = iccId;
+        this.mSlotId = slotId;
+        this.mDisplayName = displayname;
+        this.mNameSource = nameSource;
+        this.mColor = mColor;
+        this.mNumber = mNumber;
+        this.mDispalyNumberFormat = displayFormat;
+        this.mDataRoaming = roaming;
+        this.mSimIconRes = iconRes;
+    }
+
+    public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
+        public SubInfoRecord createFromParcel(Parcel source) {
+            long mSubId = source.readLong();
+            String mIccId = source.readString();
+            int mSlotId = source.readInt();
+            String mDisplayName = source.readString();
+            int mNameSource = source.readInt();
+            int mColor = source.readInt();
+            String mNumber = source.readString();
+            int mDispalyNumberFormat = source.readInt();
+            int mDataRoaming = source.readInt();
+            int[] iconRes = new int[2];
+            source.readIntArray(iconRes);
+
+            return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber,
+                mDispalyNumberFormat, mDataRoaming, iconRes);
+        }
+
+        public SubInfoRecord[] newArray(int size) {
+            return new SubInfoRecord[size];
+        }
+    };
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mSubId);
+        dest.writeString(mIccId);
+        dest.writeInt(mSlotId);
+        dest.writeString(mDisplayName);
+        dest.writeInt(mNameSource);
+        dest.writeInt(mColor);
+        dest.writeString(mNumber);
+        dest.writeInt(mDispalyNumberFormat);
+        dest.writeInt(mDataRoaming);
+        dest.writeIntArray(mSimIconRes);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
new file mode 100644
index 0000000..859a890
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -0,0 +1,708 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+import static android.Manifest.permission.READ_PHONE_STATE;
+
+import android.app.ActivityManagerNative;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.UserHandle;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.telephony.Rlog;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+/**
+ *@hide
+ */
+public class SubscriptionManager implements BaseColumns {
+    private static final String LOG_TAG = "SUB";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    // An invalid subscription identifier
+    public static final long INVALID_SUB_ID = Long.MAX_VALUE;
+
+    // The default subscription identifier
+    public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1;
+
+    public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+    public static final int DEFAULT_INT_VALUE = -100;
+
+    public static final String DEFAULT_STRING_VALUE = "N/A";
+
+    public static final int EXTRA_VALUE_NEW_SIM = 1;
+    public static final int EXTRA_VALUE_REMOVE_SIM = 2;
+    public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
+    public static final int EXTRA_VALUE_NOCHANGE = 4;
+
+    public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
+    public static final String INTENT_KEY_SIM_COUNT = "simCount";
+    public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
+    public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
+
+    /**
+     * The ICC ID of a SIM.
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String ICC_ID = "icc_id";
+
+    /**
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String SIM_ID = "sim_id";
+
+    public static final int SIM_NOT_INSERTED = -1;
+
+    /**
+     * The display name of a SIM.
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String DISPLAY_NAME = "display_name";
+
+    public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
+
+    /**
+     * The display name source of a SIM.
+     * <P>Type: INT (int)</P>
+     */
+    public static final String NAME_SOURCE = "name_source";
+
+    public static final int DEFAULT_SOURCE = 0;
+
+    public static final int SIM_SOURCE = 1;
+
+    public static final int USER_INPUT = 2;
+
+    /**
+     * The color of a SIM.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String COLOR = "color";
+
+    public static final int COLOR_1 = 0;
+
+    public static final int COLOR_2 = 1;
+
+    public static final int COLOR_3 = 2;
+
+    public static final int COLOR_4 = 3;
+
+    public static final int COLOR_DEFAULT = COLOR_1;
+
+    /**
+     * The phone number of a SIM.
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String NUMBER = "number";
+
+    /**
+     * The number display format of a SIM.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+    public static final int DISPALY_NUMBER_NONE = 0;
+
+    public static final int DISPLAY_NUMBER_FIRST = 1;
+
+    public static final int DISPLAY_NUMBER_LAST = 2;
+
+    public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
+
+    /**
+     * Permission for data roaming of a SIM.
+     * <P>Type: INTEGER (int)</P>
+     */
+    public static final String DATA_ROAMING = "data_roaming";
+
+    public static final int DATA_ROAMING_ENABLE = 1;
+
+    public static final int DATA_ROAMING_DISABLE = 0;
+
+    public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+    private static final int RES_TYPE_BACKGROUND_DARK = 0;
+
+    private static final int RES_TYPE_BACKGROUND_LIGHT = 1;
+
+    private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK);
+
+    private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT);
+
+    private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>();
+
+    public SubscriptionManager() {
+        if (DBG) logd("SubscriptionManager created");
+    }
+
+    /**
+     * Get the SubInfoRecord according to an index
+     * @param context Context provided by caller
+     * @param subId The unique SubInfoRecord index in database
+     * @return SubInfoRecord, maybe null
+     */
+    public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) {
+        if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId);
+        if (subId <= 0) {
+            if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0");
+            return null;
+        }
+
+        SubInfoRecord subInfo = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subInfo = iSub.getSubInfoUsingSubId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return subInfo;
+
+    }
+
+    /**
+     * Get the SubInfoRecord according to an IccId
+     * @param context Context provided by caller
+     * @param iccId the IccId of SIM card
+     * @return SubInfoRecord, maybe null
+     */
+    public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) {
+        if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
+        if (iccId == null) {
+            logd("[getSubInfoUsingIccId]- null iccid");
+            return null;
+        }
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSubInfoUsingIccId(iccId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the SubInfoRecord according to slotId
+     * @param context Context provided by caller
+     * @param slotId the slot which the SIM is inserted
+     * @return SubInfoRecord, maybe null
+     */
+    public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) {
+        if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId);
+        if (slotId < 0) {
+            logd("[getSubInfoUsingSlotId]- return null, slotId < 0");
+            return null;
+        }
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSubInfoUsingSlotId(slotId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get all the SubInfoRecord(s) in subinfo database
+     * @param context Context provided by caller
+     * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+     */
+    public static List<SubInfoRecord> getAllSubInfoList(Context context) {
+        if (VDBG) logd("[getAllSubInfoList]+");
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getAllSubInfoList();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+     * @param context Context provided by caller
+     * @return Array list of currently inserted SubInfoRecord(s)
+     */
+    public static List<SubInfoRecord> getActivatedSubInfoList(Context context) {
+        if (VDBG) logd("[getActivatedSubInfoList]+");
+
+        List<SubInfoRecord> result = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getActivatedSubInfoList();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the SUB count of all SUB(s) in subinfo database
+     * @param context Context provided by caller
+     * @return all SIM count in database, include what was inserted before
+     */
+    public static int getAllSubInfoCount(Context context) {
+        if (VDBG) logd("[getAllSubInfoCount]+");
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getAllSubInfoCount();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
+     * Add a new SubInfoRecord to subinfo database if needed
+     * @param context Context provided by caller
+     * @param iccId the IccId of the SIM card
+     * @param slotId the slot which the SIM is inserted
+     * @return the URL of the newly created row or the updated row
+     */
+    public static Uri addSubInfoRecord(Context context, String iccId, int slotId) {
+        if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+        if (iccId == null) {
+            logd("[addSubInfoRecord]- null iccId");
+        }
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                // FIXME: This returns 1 on success, 0 on error should should we return it?
+                iSub.addSubInfoRecord(iccId, slotId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        // FIXME: Always returns null?
+        return null;
+
+    }
+
+    /**
+     * Set SIM color by simInfo index
+     * @param context Context provided by caller
+     * @param color the color of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setColor(Context context, int color, long subId) {
+        if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId);
+        int size = sSimBackgroundDarkRes.length;
+        if (subId <= 0 || color < 0 || color >= size) {
+            logd("[setColor]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setColor(color, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set display name by simInfo index
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDisplayName(Context context, String displayName, long subId) {
+        return setDisplayName(context, displayName, subId, -1);
+    }
+
+    /**
+     * Set display name by simInfo index with name source
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+     * @return the number of records updated
+     */
+    public static int setDisplayName(Context context, String displayName, long subId, long nameSource) {
+        if (VDBG) logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource);
+        if (subId <= 0) {
+            logd("[setDisplayName]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set phone number by subId
+     * @param context Context provided by caller
+     * @param number the phone number of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDispalyNumber(Context context, String number, long subId) {
+        if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId);
+        if (number == null || subId <= 0) {
+            logd("[setDispalyNumber]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDispalyNumber(number, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+     * @param context Context provided by caller
+     * @param format the display format of phone number
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDisplayNumberFormat(Context context, int format, long subId) {
+        if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId);
+        if (format < 0 || subId <= 0) {
+            logd("[setDisplayNumberFormat]- fail, return -1");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDisplayNumberFormat(format, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    /**
+     * Set data roaming by simInfo index
+     * @param context Context provided by caller
+     * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public static int setDataRoaming(Context context, int roaming, long subId) {
+        if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
+        if (roaming < 0 || subId <= 0) {
+            logd("[setDataRoaming]- fail");
+            return -1;
+        }
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.setDataRoaming(roaming, subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    public static int getSlotId(long subId) {
+        if (VDBG) logd("[getSlotId]+ subId:" + subId);
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSlotId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+
+    }
+
+    public static long[] getSubId(int slotId) {
+        if (VDBG) logd("[getSubId]+ slotId:" + slotId);
+
+        long[] subId = null;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getSubId(slotId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return subId;
+    }
+
+    public static int getPhoneId(long subId) {
+        if (VDBG) logd("[getPhoneId]+ subId=" + subId);
+
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getPhoneId(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("[getPhoneId]- phonId=" + result);
+        return result;
+
+    }
+
+    private static int[] setSimResource(int type) {
+        int[] simResource = null;
+
+        switch (type) {
+            case RES_TYPE_BACKGROUND_DARK:
+                simResource = new int[] {
+                    com.android.internal.R.drawable.sim_dark_blue,
+                    com.android.internal.R.drawable.sim_dark_orange,
+                    com.android.internal.R.drawable.sim_dark_green,
+                    com.android.internal.R.drawable.sim_dark_purple
+                };
+                break;
+            case RES_TYPE_BACKGROUND_LIGHT:
+                simResource = new int[] {
+                    com.android.internal.R.drawable.sim_light_blue,
+                    com.android.internal.R.drawable.sim_light_orange,
+                    com.android.internal.R.drawable.sim_light_green,
+                    com.android.internal.R.drawable.sim_light_purple
+                };
+                break;
+        }
+
+        return simResource;
+    }
+
+    private static void logd(String msg) {
+        Rlog.d(LOG_TAG, "[SubManager] " + msg);
+    }
+
+    public static long normalizeSubId(long subId) {
+        long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId;
+        Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal);
+        return retVal;
+    }
+
+    public static boolean validSubId(long subId) {
+        return (subId != DEFAULT_SUB_ID) && (subId != -1);
+    }
+
+    /**
+     * @return the "system" defaultSubId on a voice capable device this
+     * will be getDefaultVoiceSubId() and on a data only device it will be
+     * getDefaultDataSubId().
+     */
+    public static long getDefaultSubId() {
+        long subId = 1;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getDefaultSubId();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("getDefaultSubId=" + subId);
+        return subId;
+    }
+
+    public static long getDefaultVoiceSubId() {
+        long subId = 1;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getDefaultVoiceSubId();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("getDefaultSubId, sub id = " + subId);
+        return subId;
+    }
+
+    public static void setDefaultVoiceSubId(long subId) {
+        if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.setDefaultVoiceSubId(subId);
+            }
+        } catch (RemoteException ex) {
+         // ignore it
+        }
+    }
+
+    public static long getPreferredSmsSubId() {
+        // FIXME add framework support to get the preferred sub
+        return getDefaultSubId();
+    }
+
+    public static long getPreferredDataSubId() {
+        // FIXME add framework support to get the preferred sub
+        return getDefaultSubId();
+    }
+
+    public static long getDefaultDataSubId() {
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                return iSub.getDefaultDataSubId();
+            } else {
+                return -1;
+            }
+        } catch (RemoteException ex) {
+            return -1;
+        }
+    }
+
+    public static void setDefaultDataSubId(long subId) {
+        if (VDBG) logd("setDataSubscription sub id = " + subId);
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.setDefaultDataSubId(subId);
+            }
+        } catch (RemoteException ex) {
+         // ignore it
+        }
+    }
+
+    public static void clearSubInfo()
+    {
+        if (VDBG) logd("[clearSubInfo]+");
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.clearSubInfo();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return;
+    }
+
+    public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
+        long [] subId = SubscriptionManager.getSubId(phoneId);
+        if ((subId != null) && (subId.length >= 1)) {
+            if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
+            intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ??
+            intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId[0]);
+        } else {
+            logd("putPhoneIdAndSubIdExtra: no valid subs");
+        }
+    }
+}
+
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3f65bca..50bbb1e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,6 +86,22 @@
 
     private final Context mContext;
 
+    private static String multiSimConfig =
+            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+
+    /** Enum indicating multisim variants
+     *  DSDS - Dual SIM Dual Standby
+     *  DSDA - Dual SIM Dual Active
+     *  TSTS - Triple SIM Triple Standby
+     **/
+    /** @hide */
+    public enum MultiSimVariants {
+        DSDS,
+        DSDA,
+        TSTS,
+        UNKNOWN
+    };
+
     /** @hide */
     public TelephonyManager(Context context) {
         Context appContext = context.getApplicationContext();
@@ -114,11 +130,61 @@
         return sInstance;
     }
 
+
+    /**
+     * Returns the multi SIM variant
+     * Returns DSDS for Dual SIM Dual Standby
+     * Returns DSDA for Dual SIM Dual Active
+     * Returns TSTS for Triple SIM Triple Standby
+     * Returns UNKNOWN for others
+     */
+    /** {@hide} */
+    public MultiSimVariants getMultiSimConfiguration() {
+        String mSimConfig =
+            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+        if (mSimConfig.equals("dsds")) {
+            return MultiSimVariants.DSDS;
+        } else if (mSimConfig.equals("dsda")) {
+            return MultiSimVariants.DSDA;
+        } else if (mSimConfig.equals("tsts")) {
+            return MultiSimVariants.TSTS;
+        } else {
+            return MultiSimVariants.UNKNOWN;
+        }
+    }
+
+
+    /**
+     * Returns the number of phones available.
+     * Returns 1 for Single standby mode (Single SIM functionality)
+     * Returns 2 for Dual standby mode.(Dual SIM functionality)
+     */
+    /** {@hide} */
+    public int getPhoneCount() {
+        int phoneCount = 1;
+        switch (getMultiSimConfiguration()) {
+            case DSDS:
+            case DSDA:
+                phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+                break;
+            case TSTS:
+                phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM;
+                break;
+        }
+        return phoneCount;
+    }
+
     /** {@hide} */
     public static TelephonyManager from(Context context) {
         return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
     }
 
+    /** {@hide} */
+    public boolean isMultiSimEnabled() {
+        return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
+            multiSimConfig.equals("tsts"));
+    }
+
     //
     // Broadcast Intent actions
     //
@@ -529,8 +595,23 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getDeviceId() {
+        return getDeviceId(getDefaultSim());
+    }
+
+    /**
+     * Returns the unique device ID of a subscription, for example, the IMEI for
+     * GSM and the MEID for CDMA phones. Return null if device ID is not available.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param slotId of which deviceID is returned
+     */
+    /** {@hide} */
+    public String getDeviceId(int slotId) {
+        long[] subId = SubscriptionManager.getSubId(slotId);
         try {
-            return getSubscriberInfo().getDeviceId();
+            return getSubscriberInfo().getDeviceIdUsingSubId(subId[0]);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -578,8 +659,23 @@
      * @hide
      */
     public void enableLocationUpdates() {
+            enableLocationUpdates(getDefaultSubscription());
+    }
+
+    /**
+     * Enables location update notifications for a subscription.
+     * {@link PhoneStateListener#onCellLocationChanged
+     * PhoneStateListener.onCellLocationChanged} will be called on location updates.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
+     * CONTROL_LOCATION_UPDATES}
+     *
+     * @param subId for which the location updates are enabled
+     */
+    /** @hide */
+    public void enableLocationUpdates(long subId) {
         try {
-            getITelephony().enableLocationUpdates();
+            getITelephony().enableLocationUpdatesUsingSubId(subId);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -595,8 +691,13 @@
      * @hide
      */
     public void disableLocationUpdates() {
+            disableLocationUpdates(getDefaultSubscription());
+    }
+
+    /** @hide */
+    public void disableLocationUpdates(long subId) {
         try {
-            getITelephony().disableLocationUpdates();
+            getITelephony().disableLocationUpdatesUsingSubId(subId);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -644,22 +745,37 @@
      * {@hide}
      */
     public int getCurrentPhoneType() {
+        return getCurrentPhoneType(getDefaultSubscription());
+    }
+
+    /**
+     * Returns a constant indicating the device phone type for a subscription.
+     *
+     * @see #PHONE_TYPE_NONE
+     * @see #PHONE_TYPE_GSM
+     * @see #PHONE_TYPE_CDMA
+     *
+     * @param subId for which phone type is returned
+     */
+    /** {@hide} */
+    public int getCurrentPhoneType(long subId) {
+
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getActivePhoneType();
+                return telephony.getActivePhoneTypeUsingSubId(subId);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
-                return getPhoneTypeFromProperty();
+                return getPhoneTypeFromProperty(subId);
             }
         } catch (RemoteException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
-            return getPhoneTypeFromProperty();
+            return getPhoneTypeFromProperty(subId);
         } catch (NullPointerException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
-            return getPhoneTypeFromProperty();
+            return getPhoneTypeFromProperty(subId);
         }
     }
 
@@ -680,20 +796,35 @@
     }
 
     private int getPhoneTypeFromProperty() {
-        int type =
-            SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE,
-                    getPhoneTypeFromNetworkType());
-        return type;
+        return getPhoneTypeFromProperty(getDefaultSubscription());
+    }
+
+    /** {@hide} */
+    private int getPhoneTypeFromProperty(long subId) {
+        String type =
+            getTelephonyProperty
+                (TelephonyProperties.CURRENT_ACTIVE_PHONE, subId, null);
+        if (type != null) {
+            return (Integer.parseInt(type));
+        } else {
+            return getPhoneTypeFromNetworkType(subId);
+        }
     }
 
     private int getPhoneTypeFromNetworkType() {
+        return getPhoneTypeFromNetworkType(getDefaultSubscription());
+    }
+
+    /** {@hide} */
+    private int getPhoneTypeFromNetworkType(long subId) {
         // When the system property CURRENT_ACTIVE_PHONE, has not been set,
         // use the system property for default network type.
         // This is a fail safe, and can only happen at first boot.
-        int mode = SystemProperties.getInt("ro.telephony.default_network", -1);
-        if (mode == -1)
-            return PHONE_TYPE_NONE;
-        return getPhoneType(mode);
+        String mode = getTelephonyProperty("ro.telephony.default_network", subId, null);
+        if (mode != null) {
+            return TelephonyManager.getPhoneType(Integer.parseInt(mode));
+        }
+        return TelephonyManager.PHONE_TYPE_NONE;
     }
 
     /**
@@ -828,7 +959,23 @@
      * on a CDMA network).
      */
     public String getNetworkOperatorName() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA);
+        return getNetworkOperatorName(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the alphabetic name of current registered operator
+     * for a particular subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     * @param subId
+     */
+    /** {@hide} */
+    public String getNetworkOperatorName(long subId) {
+
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
+                subId, "");
     }
 
     /**
@@ -839,17 +986,48 @@
      * on a CDMA network).
      */
     public String getNetworkOperator() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC);
+        return getNetworkOperator(getDefaultSubscription());
     }
 
     /**
+     * Returns the numeric name (MCC+MNC) of current registered operator
+     * for a particular subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     *
+     * @param subId
+     */
+    /** {@hide} */
+   public String getNetworkOperator(long subId) {
+
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC,
+                subId, "");
+     }
+
+    /**
      * Returns true if the device is considered roaming on the current
      * network, for GSM purposes.
      * <p>
      * Availability: Only when user registered to a network.
      */
     public boolean isNetworkRoaming() {
-        return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
+        return isNetworkRoaming(getDefaultSubscription());
+    }
+
+    /**
+     * Returns true if the device is considered roaming on the current
+     * network for a subscription.
+     * <p>
+     * Availability: Only when user registered to a network.
+     *
+     * @param subId
+     */
+    /** {@hide} */
+    public boolean isNetworkRoaming(long subId) {
+        return "true".equals(getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
+                subId, null));
     }
 
     /**
@@ -861,7 +1039,23 @@
      * on a CDMA network).
      */
     public String getNetworkCountryIso() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
+        return getNetworkCountryIso(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the ISO country code equivalent of the current registered
+     * operator's MCC (Mobile Country Code) of a subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     *
+     * @param subId for which Network CountryIso is returned
+     */
+    /** {@hide} */
+    public String getNetworkCountryIso(long subId) {
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
+                subId, "");
     }
 
     /** Network type is unknown */
@@ -908,6 +1102,49 @@
 
     /**
      * Returns a constant indicating the radio technology (network type)
+     * currently in use on the device for a subscription.
+     * @return the network type
+     *
+     * @param subId for which network type is returned
+     *
+     * @see #NETWORK_TYPE_UNKNOWN
+     * @see #NETWORK_TYPE_GPRS
+     * @see #NETWORK_TYPE_EDGE
+     * @see #NETWORK_TYPE_UMTS
+     * @see #NETWORK_TYPE_HSDPA
+     * @see #NETWORK_TYPE_HSUPA
+     * @see #NETWORK_TYPE_HSPA
+     * @see #NETWORK_TYPE_CDMA
+     * @see #NETWORK_TYPE_EVDO_0
+     * @see #NETWORK_TYPE_EVDO_A
+     * @see #NETWORK_TYPE_EVDO_B
+     * @see #NETWORK_TYPE_1xRTT
+     * @see #NETWORK_TYPE_IDEN
+     * @see #NETWORK_TYPE_LTE
+     * @see #NETWORK_TYPE_EHRPD
+     * @see #NETWORK_TYPE_HSPAP
+     */
+    /** {@hide} */
+   public int getNetworkType(long subId) {
+       try {
+           ITelephony telephony = getITelephony();
+           if (telephony != null) {
+               return telephony.getNetworkTypeUsingSubId(subId);
+           } else {
+               // This can happen when the ITelephony interface is not up yet.
+               return NETWORK_TYPE_UNKNOWN;
+           }
+       } catch(RemoteException ex) {
+           // This shouldn't happen in the normal case
+           return NETWORK_TYPE_UNKNOWN;
+       } catch (NullPointerException ex) {
+           // This could happen before phone restarts due to crashing
+           return NETWORK_TYPE_UNKNOWN;
+       }
+   }
+
+    /**
+     * Returns a constant indicating the radio technology (network type)
      * currently in use on the device for data transmission.
      * @return the network type
      *
@@ -931,10 +1168,22 @@
      * @hide
      */
     public int getDataNetworkType() {
+        return getDataNetworkType(getDefaultSubscription());
+    }
+
+    /**
+     * Returns a constant indicating the radio technology (network type)
+     * currently in use on the device for data transmission for a subscription
+     * @return the network type
+     *
+     * @param subId for which network type is returned
+     */
+    /** {@hide} */
+    public int getDataNetworkType(long subId) {
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getDataNetworkType();
+                return telephony.getDataNetworkTypeUsingSubId(subId);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -954,10 +1203,19 @@
      * @hide
      */
     public int getVoiceNetworkType() {
+        return getVoiceNetworkType(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the NETWORK_TYPE_xxxx for voice for a subId
+     *
+     */
+    /** {@hide} */
+    public int getVoiceNetworkType(long subId) {
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getVoiceNetworkType();
+                return telephony.getVoiceNetworkTypeUsingSubId(subId);
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -1023,6 +1281,13 @@
         return getNetworkTypeName(getNetworkType());
     }
 
+    /**
+     * Returns a string representation of the radio technology (network type)
+     * currently in use on the device.
+     * @param subId for which network type is returned
+     * @return the name of the radio technology
+     *
+     */
     /** {@hide} */
     public static String getNetworkTypeName(int type) {
         switch (type) {
@@ -1093,8 +1358,20 @@
      * @return true if a ICC card is present
      */
     public boolean hasIccCard() {
+        return hasIccCard(getDefaultSim());
+    }
+
+    /**
+     * @return true if a ICC card is present for a subscription
+     *
+     * @param slotId for which icc card presence is checked
+     */
+    /** {@hide} */
+    // FIXME Input argument slotId should be of type int
+    public boolean hasIccCard(long slotId) {
+
         try {
-            return getITelephony().hasIccCard();
+            return getITelephony().hasIccCardUsingSlotId(slotId);
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return false;
@@ -1117,7 +1394,33 @@
      * @see #SIM_STATE_CARD_IO_ERROR
      */
     public int getSimState() {
-        String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE);
+        return getSimState(getDefaultSim());
+    }
+
+    /**
+     * Returns a constant indicating the state of the
+     * device SIM card in a slot.
+     *
+     * @param slotId
+     *
+     * @see #SIM_STATE_UNKNOWN
+     * @see #SIM_STATE_ABSENT
+     * @see #SIM_STATE_PIN_REQUIRED
+     * @see #SIM_STATE_PUK_REQUIRED
+     * @see #SIM_STATE_NETWORK_LOCKED
+     * @see #SIM_STATE_READY
+     */
+    /** {@hide} */
+    // FIXME the argument to pass is subId ??
+    public int getSimState(int slotId) {
+        long[] subId = SubscriptionManager.getSubId(slotId);
+        if (subId == null) {
+            return SIM_STATE_ABSENT;
+        }
+        // FIXME Do not use a property to determine SIM_STATE, call
+        // appropriate method on some object.
+        String prop =
+            getTelephonyProperty(TelephonyProperties.PROPERTY_SIM_STATE, subId[0], "");
         if ("ABSENT".equals(prop)) {
             return SIM_STATE_ABSENT;
         }
@@ -1150,7 +1453,27 @@
      * @see #getSimState
      */
     public String getSimOperator() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
+        long subId = getDefaultSubscription();
+        Rlog.d(TAG, "getSimOperator(): default subId=" + subId);
+        return getSimOperator(subId);
+    }
+
+    /**
+     * Returns the MCC+MNC (mobile country code + mobile network code) of the
+     * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
+     * <p>
+     * Availability: SIM state must be {@link #SIM_STATE_READY}
+     *
+     * @see #getSimState
+     *
+     * @param subId for which SimOperator is returned
+     */
+    /** {@hide} */
+    public String getSimOperator(long subId) {
+        String operator = getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC,
+                subId, "");
+        Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator);
+        return operator;
     }
 
     /**
@@ -1161,14 +1484,40 @@
      * @see #getSimState
      */
     public String getSimOperatorName() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA);
+        return getSimOperatorName(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the Service Provider Name (SPN).
+     * <p>
+     * Availability: SIM state must be {@link #SIM_STATE_READY}
+     *
+     * @see #getSimState
+     *
+     * @param subId for which SimOperatorName is returned
+     */
+    /** {@hide} */
+    public String getSimOperatorName(long subId) {
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
+                subId, "");
     }
 
     /**
      * Returns the ISO country code equivalent for the SIM provider's country code.
      */
     public String getSimCountryIso() {
-        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY);
+        return getSimCountryIso(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the ISO country code equivalent for the SIM provider's country code.
+     *
+     * @param subId for which SimCountryIso is returned
+     */
+    /** {@hide} */
+    public String getSimCountryIso(long subId) {
+        return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+                subId, "");
     }
 
     /**
@@ -1179,8 +1528,21 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getSimSerialNumber() {
+         return getSimSerialNumber(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the serial number for the given subscription, if applicable. Return null if it is
+     * unavailable.
+     * <p>
+     * @param subId for which Sim Serial number is returned
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     */
+    /** {@hide} */
+    public String getSimSerialNumber(long subId) {
         try {
-            return getSubscriberInfo().getIccSerialNumber();
+            return getSubscriberInfo().getIccSerialNumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1200,8 +1562,23 @@
      * @hide
      */
     public int getLteOnCdmaMode() {
+        return getLteOnCdmaMode(getDefaultSubscription());
+    }
+
+    /**
+     * Return if the current radio is LTE on CDMA for Subscription. This
+     * is a tri-state return value as for a period of time
+     * the mode may be unknown.
+     *
+     * @param subId for which radio is LTE on CDMA is returned
+     * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
+     * or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
+     *
+     */
+    /** {@hide} */
+    public int getLteOnCdmaMode(long subId) {
         try {
-            return getITelephony().getLteOnCdmaMode();
+            return getITelephony().getLteOnCdmaModeUsingSubId(subId);
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
@@ -1225,8 +1602,23 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getSubscriberId() {
+        return getSubscriberId(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the unique subscriber ID, for example, the IMSI for a GSM phone
+     * for a subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId whose subscriber id is returned
+     */
+    /** {@hide} */
+    public String getSubscriberId(long subId) {
         try {
-            return getSubscriberInfo().getSubscriberId();
+            return getSubscriberInfo().getSubscriberIdUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1254,6 +1646,27 @@
     }
 
     /**
+     * Returns the Group Identifier Level1 for a GSM phone for a particular subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subscription whose subscriber id is returned
+     */
+    /** {@hide} */
+    public String getGroupIdLevel1(long subId) {
+        try {
+            return getSubscriberInfo().getGroupIdLevel1UsingSubId(subId);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
      * Returns the phone number string for line 1, for example, the MSISDN
      * for a GSM phone. Return null if it is unavailable.
      * <p>
@@ -1261,8 +1674,22 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getLine1Number() {
+        return getLine1Number(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the phone number string for line 1, for example, the MSISDN
+     * for a GSM phone for a particular subscription. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId whose phone number for line 1 is returned
+     */
+    /** {@hide} */
+    public String getLine1Number(long subId) {
         try {
-            return getSubscriberInfo().getLine1Number();
+            return getSubscriberInfo().getLine1NumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1281,8 +1708,23 @@
      * nobody seems to call this.
      */
     public String getLine1AlphaTag() {
+        return getLine1AlphaTag(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the alphabetic identifier associated with the line 1 number
+     * for a subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose alphabetic identifier associated with line 1 is returned
+     * nobody seems to call this.
+     */
+    /** {@hide} */
+    public String getLine1AlphaTag(long subId) {
         try {
-            return getSubscriberInfo().getLine1AlphaTag();
+            return getSubscriberInfo().getLine1AlphaTagUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1301,8 +1743,22 @@
      * @hide
      */
     public String getMsisdn() {
+        return getMsisdn(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the MSISDN string.
+     * for a GSM phone. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId for which msisdn is returned
+     */
+    /** {@hide} */
+    public String getMsisdn(long subId) {
         try {
-            return getSubscriberInfo().getMsisdn();
+            return getSubscriberInfo().getMsisdnUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1318,8 +1774,21 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getVoiceMailNumber() {
+        return getVoiceMailNumber(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the voice mail number for a subscription.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose voice mail number is returned
+     */
+    /** {@hide} */
+    public String getVoiceMailNumber(long subId) {
         try {
-            return getSubscriberInfo().getVoiceMailNumber();
+            return getSubscriberInfo().getVoiceMailNumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1337,8 +1806,21 @@
      * @hide
      */
     public String getCompleteVoiceMailNumber() {
+        return getCompleteVoiceMailNumber(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the complete voice mail number. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
+     *
+     * @param subId
+     */
+    /** {@hide} */
+    public String getCompleteVoiceMailNumber(long subId) {
         try {
-            return getSubscriberInfo().getCompleteVoiceMailNumber();
+            return getSubscriberInfo().getCompleteVoiceMailNumberUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1355,8 +1837,20 @@
      * @hide
      */
     public int getVoiceMessageCount() {
+        return getVoiceMessageCount(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the voice mail count for a subscription. Return 0 if unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose voice message count is returned
+     */
+    /** {@hide} */
+    public int getVoiceMessageCount(long subId) {
         try {
-            return getITelephony().getVoiceMessageCount();
+            return getITelephony().getVoiceMessageCountUsingSubId(subId);
         } catch (RemoteException ex) {
             return 0;
         } catch (NullPointerException ex) {
@@ -1373,8 +1867,22 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getVoiceMailAlphaTag() {
+        return getVoiceMailAlphaTag(getDefaultSubscription());
+    }
+
+    /**
+     * Retrieves the alphabetic identifier associated with the voice
+     * mail number for a subscription.
+     * <p>
+     * Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * @param subId whose alphabetic identifier associated with the
+     * voice mail number is returned
+     */
+    /** {@hide} */
+    public String getVoiceMailAlphaTag(long subId) {
         try {
-            return getSubscriberInfo().getVoiceMailAlphaTag();
+            return getSubscriberInfo().getVoiceMailAlphaTagUsingSubId(subId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1437,7 +1945,6 @@
         return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
     }
 
-
     /** Device call state: No activity. */
     public static final int CALL_STATE_IDLE = 0;
     /** Device call state: Ringing. A new call arrived and is
@@ -1453,8 +1960,19 @@
      * Returns a constant indicating the call state (cellular) on the device.
      */
     public int getCallState() {
+        return getCallState(getDefaultSubscription());
+    }
+
+    /**
+     * Returns a constant indicating the call state (cellular) on the device
+     * for a subscription.
+     *
+     * @param subId whose call state is returned
+     */
+    /** {@hide} */
+    public int getCallState(long subId) {
         try {
-            return getITelephony().getCallState();
+            return getITelephony().getCallStateUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return CALL_STATE_IDLE;
@@ -1575,8 +2093,8 @@
     public void listen(PhoneStateListener listener, int events) {
         String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
         try {
-            Boolean notifyNow = true;
-            sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
+            Boolean notifyNow = (getITelephony() != null);
+            sRegistry.listenUsingSubId(listener.mSubId, pkgForDebug, listener.callback, events, notifyNow);
         } catch (RemoteException ex) {
             // system process dead
         } catch (NullPointerException ex) {
@@ -1590,8 +2108,16 @@
      * @hide
      */
     public int getCdmaEriIconIndex() {
+        return getCdmaEriIconIndex(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the CDMA ERI icon index to display for a subscription
+     */
+    /** {@hide} */
+    public int getCdmaEriIconIndex(long subId) {
         try {
-            return getITelephony().getCdmaEriIconIndex();
+            return getITelephony().getCdmaEriIconIndexUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
@@ -1608,8 +2134,18 @@
      * @hide
      */
     public int getCdmaEriIconMode() {
+        return getCdmaEriIconMode(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the CDMA ERI icon mode for a subscription.
+     * 0 - ON
+     * 1 - FLASHING
+     */
+    /** {@hide} */
+    public int getCdmaEriIconMode(long subId) {
         try {
-            return getITelephony().getCdmaEriIconMode();
+            return getITelephony().getCdmaEriIconModeUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
@@ -1624,8 +2160,17 @@
      * @hide
      */
     public String getCdmaEriText() {
+        return getCdmaEriText(getDefaultSubscription());
+    }
+
+    /**
+     * Returns the CDMA ERI text, of a subscription
+     *
+     */
+    /** {@hide} */
+    public String getCdmaEriText(long subId) {
         try {
-            return getITelephony().getCdmaEriText();
+            return getITelephony().getCdmaEriTextUsingSubId(subId);
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return null;
@@ -1924,6 +2469,286 @@
     }
 
     /**
+     * Returns Default subscription.
+     */
+    private static long getDefaultSubscription() {
+        return SubscriptionManager.getDefaultSubId();
+    }
+
+    /** {@hide} */
+    public int getDefaultSim() {
+        //TODO Need to get it from Telephony Devcontroller
+        return 0;
+    }
+
+    /**
+     * Sets the telephony property with the value specified.
+     *
+     * @hide
+     */
+    public static void setTelephonyProperty(String property, long subId, String value) {
+        String propVal = "";
+        String p[] = null;
+        String prop = SystemProperties.get(property);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+
+        if (value == null) {
+            value = "";
+        }
+
+        if (prop != null) {
+            p = prop.split(",");
+        }
+
+        if (phoneId < 0) return;
+
+        for (int i = 0; i < phoneId; i++) {
+            String str = "";
+            if ((p != null) && (i < p.length)) {
+                str = p[i];
+            }
+            propVal = propVal + str + ",";
+        }
+
+        propVal = propVal + value;
+        if (p != null) {
+            for (int i = phoneId + 1; i < p.length; i++) {
+                propVal = propVal + "," + p[i];
+            }
+        }
+
+        // TODO: workaround for QC
+        if (property.length() > SystemProperties.PROP_NAME_MAX || propVal.length() > SystemProperties.PROP_VALUE_MAX) {
+            Rlog.d(TAG, "setTelephonyProperty length too long:" + property + ", " + propVal);
+            return;
+        }
+
+        Rlog.d(TAG, "setTelephonyProperty property=" + property + " propVal=" + propVal);
+        SystemProperties.set(property, propVal);
+    }
+
+    /**
+     * Convenience function for retrieving a value from the secure settings
+     * value list as an integer.  Note that internally setting values are
+     * always stored as strings; this function converts the string to an
+     * integer for you.
+     * <p>
+     * This version does not take a default value.  If the setting has not
+     * been set, or the string value is not a number,
+     * it throws {@link SettingNotFoundException}.
+     *
+     * @param cr The ContentResolver to access.
+     * @param name The name of the setting to retrieve.
+     * @param index The index of the list
+     *
+     * @throws SettingNotFoundException Thrown if a setting by the given
+     * name can't be found or the setting value is not an integer.
+     *
+     * @return The value at the given index of settings.
+     * @hide
+     */
+    public static int getIntAtIndex(android.content.ContentResolver cr,
+            String name, int index)
+            throws android.provider.Settings.SettingNotFoundException {
+        String v = android.provider.Settings.Global.getString(cr, name);
+        if (v != null) {
+            String valArray[] = v.split(",");
+            if ((index >= 0) && (index < valArray.length) && (valArray[index] != null)) {
+                try {
+                    return Integer.parseInt(valArray[index]);
+                } catch (NumberFormatException e) {
+                    //Log.e(TAG, "Exception while parsing Integer: ", e);
+                }
+            }
+        }
+        throw new android.provider.Settings.SettingNotFoundException(name);
+    }
+
+    /**
+     * Convenience function for updating settings value as coma separated
+     * integer values. This will either create a new entry in the table if the
+     * given name does not exist, or modify the value of the existing row
+     * with that name.  Note that internally setting values are always
+     * stored as strings, so this function converts the given value to a
+     * string before storing it.
+     *
+     * @param cr The ContentResolver to access.
+     * @param name The name of the setting to modify.
+     * @param index The index of the list
+     * @param value The new value for the setting to be added to the list.
+     * @return true if the value was set, false on database errors
+     * @hide
+     */
+    public static boolean putIntAtIndex(android.content.ContentResolver cr,
+            String name, int index, int value) {
+        String data = "";
+        String valArray[] = null;
+        String v = android.provider.Settings.Global.getString(cr, name);
+
+        if (v != null) {
+            valArray = v.split(",");
+        }
+
+        // Copy the elements from valArray till index
+        for (int i = 0; i < index; i++) {
+            String str = "";
+            if ((valArray != null) && (i < valArray.length)) {
+                str = valArray[i];
+            }
+            data = data + str + ",";
+        }
+
+        data = data + value;
+
+        // Copy the remaining elements from valArray if any.
+        if (valArray != null) {
+            for (int i = index+1; i < valArray.length; i++) {
+                data = data + "," + valArray[i];
+            }
+        }
+        return android.provider.Settings.Global.putString(cr, name, data);
+    }
+
+    /**
+     * Gets the telephony property.
+     *
+     * @hide
+     */
+    public static String getTelephonyProperty(String property, long subId, String defaultVal) {
+        String propVal = null;
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+        String prop = SystemProperties.get(property);
+        if ((prop != null) && (prop.length() > 0)) {
+            String values[] = prop.split(",");
+            if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) {
+                propVal = values[phoneId];
+            }
+        }
+        return propVal == null ? defaultVal : propVal;
+    }
+
+    /** @hide */
+    public int getSimCount() {
+        if(isMultiSimEnabled()) {
+        //TODO Need to get it from Telephony Devcontroller
+            return 2;
+        } else {
+           return 1;
+        }
+    }
+
+    /**
+     * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+     * @return IMS Service Table or null if not present or not loaded
+     * @hide
+     */
+    public String getIsimIst() {
+        try {
+            return getSubscriberInfo().getIsimIst();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+     * @return an array of PCSCF strings with one PCSCF per string, or null if
+     *         not present or not loaded
+     * @hide
+     */
+    public String[] getIsimPcscf() {
+        try {
+            return getSubscriberInfo().getIsimPcscf();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the response of ISIM Authetification through RIL.
+     * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo.
+     * @return the response of ISIM Authetification, or null if not available
+     * @hide
+     * @deprecated
+     * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+     */
+    public String getIsimChallengeResponse(String nonce){
+        try {
+            return getSubscriberInfo().getIsimChallengeResponse(nonce);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
+     * Returns the response of SIM Authentication through RIL.
+     * Returns null if the Authentication hasn't been successful
+     * @param subId subscription ID to be queried
+     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param data authentication challenge data
+     * @return the response of SIM Authentication, or null if not available
+     * @hide
+     */
+    public String getIccSimChallengeResponse(long subId, int appType, String data) {
+        try {
+            return getSubscriberInfo().getIccSimChallengeResponse(subId, appType, data);
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone starts
+            return null;
+        }
+    }
+
+    /**
+     * Returns the response of SIM Authentication through RIL for the default subscription.
+     * Returns null if the Authentication hasn't been successful
+     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param data authentication challenge data
+     * @return the response of SIM Authentication, or null if not available
+     * @hide
+     */
+    public String getIccSimChallengeResponse(int appType, String data) {
+        return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+    }
+
+    /**
+     * Get P-CSCF address from PCO after data connection is established or modified.
+     *
+     * @return array of P-CSCF address
+     * @hide
+     */
+    public String[] getPcscfAddress() {
+        try {
+            return getITelephony().getPcscfAddress();
+        } catch (RemoteException e) {
+            return new String[0];
+        }
+    }
+
+    /**
+     * Set IMS registration state
+     *
+     * @param Registration state
+     * @hide
+     */
+    public void setImsRegistrationState(boolean registered) {
+        try {
+            getITelephony().setImsRegistrationState(registered);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Get the preferred network type.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/telephony/java/android/telephony/VoLteServiceState.aidl b/telephony/java/android/telephony/VoLteServiceState.aidl
new file mode 100644
index 0000000..59dd04f
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable VoLteServiceState;
+
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
new file mode 100644
index 0000000..afef601b
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Contains LTE network state related information.
+ *
+ * @hide
+ */
+public final class VoLteServiceState implements Parcelable {
+
+    private static final String LOG_TAG = "VoLteServiceState";
+    private static final boolean DBG = false;
+
+    //Use int max, as -1 is a valid value in signal strength
+    public static final int INVALID = 0x7FFFFFFF;
+
+    public static final int NOT_SUPPORTED = 0;
+    public static final int SUPPORTED = 1;
+
+    // Single Radio Voice Call Continuity(SRVCC) progress state
+    public static final int HANDOVER_STARTED   = 0;
+    public static final int HANDOVER_COMPLETED = 1;
+    public static final int HANDOVER_FAILED    = 2;
+    public static final int HANDOVER_CANCELED  = 3;
+
+    private int mSrvccState;
+
+    /**
+     * Create a new VoLteServiceState from a intent notifier Bundle
+     *
+     * This method is used by PhoneStateIntentReceiver and maybe by
+     * external applications.
+     *
+     * @param m Bundle from intent notifier
+     * @return newly created VoLteServiceState
+     *
+     * @hide
+     */
+    public static VoLteServiceState newFromBundle(Bundle m) {
+        VoLteServiceState ret;
+        ret = new VoLteServiceState();
+        ret.setFromNotifierBundle(m);
+        return ret;
+    }
+
+    /**
+     * Empty constructor
+     *
+     * @hide
+     */
+    public VoLteServiceState() {
+        initialize();
+    }
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public VoLteServiceState(int srvccState) {
+        initialize();
+
+        mSrvccState = srvccState;
+    }
+
+    /**
+     * Copy constructors
+     *
+     * @param s Source VoLteServiceState
+     *
+     * @hide
+     */
+    public VoLteServiceState(VoLteServiceState s) {
+        copyFrom(s);
+    }
+
+    /**
+     * Initialize values to defaults.
+     *
+     * @hide
+     */
+    private void initialize() {
+        mSrvccState = INVALID;
+    }
+
+    /**
+     * @hide
+     */
+    protected void copyFrom(VoLteServiceState s) {
+        mSrvccState = s.mSrvccState;
+    }
+
+    /**
+     * Construct a VoLteServiceState object from the given parcel.
+     *
+     * @hide
+     */
+    public VoLteServiceState(Parcel in) {
+        if (DBG) log("Size of VoLteServiceState parcel:" + in.dataSize());
+
+        mSrvccState = in.readInt();
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSrvccState);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     *
+     * @hide
+     */
+    public static final Parcelable.Creator<VoLteServiceState> CREATOR = new Parcelable.Creator() {
+        public VoLteServiceState createFromParcel(Parcel in) {
+            return new VoLteServiceState(in);
+        }
+
+        public VoLteServiceState[] newArray(int size) {
+            return new VoLteServiceState[size];
+        }
+    };
+
+    /**
+     * Validate the individual fields as per the range
+     * specified in ril.h
+     * Set to invalid any field that is not in the valid range
+     *
+     * @return
+     *      Valid values for all fields
+     * @hide
+     */
+    public void validateInput() {
+    }
+
+    public int hashCode() {
+        int primeNum = 31;
+        return ((mSrvccState * primeNum));
+    }
+
+    /**
+     * @return true if the LTE network states are the same
+     */
+    @Override
+    public boolean equals (Object o) {
+        VoLteServiceState s;
+
+        try {
+            s = (VoLteServiceState) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return (mSrvccState == s.mSrvccState);
+    }
+
+    /**
+     * @return string representation.
+     */
+    @Override
+    public String toString() {
+        return ("VoLteServiceState:"
+                + " " + mSrvccState);
+    }
+
+    /**
+     * Set VoLteServiceState based on intent notifier map
+     *
+     * @param m intent notifier map
+     * @hide
+     */
+    private void setFromNotifierBundle(Bundle m) {
+        mSrvccState = m.getInt("mSrvccState");
+    }
+
+    /**
+     * Set intent notifier Bundle based on VoLteServiceState
+     *
+     * @param m intent notifier Bundle
+     * @hide
+     */
+    public void fillInNotifierBundle(Bundle m) {
+        m.putInt("mSrvccState", mSrvccState);
+    }
+
+    public int getSrvccState() {
+        return mSrvccState;
+    }
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index f8dd7cf..745c9d0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -37,6 +37,9 @@
 import com.android.i18n.phonenumbers.NumberParseException;
 import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import android.telephony.SubscriptionManager;
+
+import android.telephony.TelephonyManager;
 
 import java.util.Locale;
 
@@ -233,6 +236,7 @@
                 info.contactExists = true;
             }
             cursor.close();
+            cursor = null;
         }
 
         info.needUpdate = false;
@@ -269,6 +273,23 @@
     public static CallerInfo getCallerInfo(Context context, String number) {
         if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
 
+        long subId = SubscriptionManager.getDefaultSubId();
+        return getCallerInfo(context, number, subId);
+    }
+
+    /**
+     * getCallerInfo given a phone number and subscription, look up in the call-log database
+     * for the matching caller id info.
+     * @param context the context used to get the ContentResolver
+     * @param number the phone number used to lookup caller id
+     * @param subId the subscription for checking for if voice mail number or not
+     * @return the CallerInfo which contains the caller id for the given
+     * number. The returned CallerInfo is null if no number is supplied. If
+     * a matching number is not found, then a generic caller info is returned,
+     * with all relevant fields empty or null.
+     */
+    public static CallerInfo getCallerInfo(Context context, String number, long subId) {
+
         if (TextUtils.isEmpty(number)) {
             return null;
         }
@@ -278,7 +299,7 @@
         // shortcut and skip the query.
         if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
             return new CallerInfo().markAsEmergency(context);
-        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+        } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
             return new CallerInfo().markAsVoiceMail();
         }
 
@@ -400,10 +421,17 @@
     // TODO: As in the emergency number handling, we end up writing a
     // string in the phone number field.
     /* package */ CallerInfo markAsVoiceMail() {
+
+        long subId = SubscriptionManager.getDefaultSubId();
+        return markAsVoiceMail(subId);
+
+    }
+
+    /* package */ CallerInfo markAsVoiceMail(long subId) {
         mIsVoiceMail = true;
 
         try {
-            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(subId);
 
             phoneNumber = voiceMailLabel;
         } catch (SecurityException se) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 34fed5e..fe403d9 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,12 +24,15 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.PhoneLookup;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 /**
  * Helper class to make it easier to run asynchronous caller-id lookup queries.
@@ -75,6 +78,8 @@
         public Object cookie;
         public int event;
         public String number;
+
+        public long subId;
     }
 
 
@@ -207,11 +212,17 @@
                 // However, if there is any code that calls this method, we should
                 // check the parameters to make sure they're viable.
                 if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
+                if (cursor != null) {
+                    cursor.close();
+                }
                 return;
             }
 
             if (cw.event == EVENT_END_OF_QUEUE) {
                 release();
+                if (cursor != null) {
+                    cursor.close();
+                }
                 return;
             }
 
@@ -232,7 +243,7 @@
                     // comments at the top of CallerInfo class).
                     mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
                 } else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
-                    mCallerInfo = new CallerInfo().markAsVoiceMail();
+                    mCallerInfo = new CallerInfo().markAsVoiceMail(cw.subId);
                 } else {
                     mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
                     if (DBG) Rlog.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo);
@@ -289,6 +300,10 @@
                              " for token: " + token + mCallerInfo);
                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
             }
+
+            if (cursor != null) {
+               cursor.close();
+            }
         }
     }
 
@@ -334,6 +349,25 @@
      */
     public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
             OnQueryCompleteListener listener, Object cookie) {
+
+        long subId = SubscriptionManager.getDefaultSubId();
+        return startQuery(token, context, number, listener, cookie, subId);
+    }
+
+    /**
+     * Factory method to start the query based on a number with specific subscription.
+     *
+     * Note: if the number contains an "@" character we treat it
+     * as a SIP address, and look it up directly in the Data table
+     * rather than using the PhoneLookup table.
+     * TODO: But eventually we should expose two separate methods, one for
+     * numbers and one for SIP addresses, and then have
+     * PhoneUtils.startGetCallerInfo() decide which one to call based on
+     * the phone type of the incoming connection.
+     */
+    public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
+            OnQueryCompleteListener listener, Object cookie, long subId) {
+
         if (DBG) {
             Rlog.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####");
             Rlog.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx");
@@ -397,11 +431,12 @@
         cw.listener = listener;
         cw.cookie = cookie;
         cw.number = number;
+        cw.subId = subId;
 
         // check to see if these are recognized numbers, and use shortcuts if we can.
         if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
             cw.event = EVENT_EMERGENCY_NUMBER;
-        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+        } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
             cw.event = EVENT_VOICEMAIL_NUMBER;
         } else {
             cw.event = EVENT_NEW_QUERY;
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3f36645..a95336e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -23,6 +23,7 @@
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
+import android.telephony.VoLteServiceState;
 
 oneway interface IPhoneStateListener {
     void onServiceStateChanged(in ServiceState serviceState);
@@ -41,5 +42,6 @@
     void onPreciseCallStateChanged(in PreciseCallState callState);
     void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
     void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
+    void onVoLteServiceStateChanged(in VoLteServiceState lteState);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 03940dc..4734965 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -28,6 +28,13 @@
     String getDeviceId();
 
     /**
+     * Retrieves the unique device ID of a subId for the device, e.g., IMEI
+     * for GSM phones.
+     */
+    String getDeviceIdUsingSubId(long subId);
+
+
+    /**
      * Retrieves the software version number for the device, e.g., IMEI/SV
      * for GSM phones.
      */
@@ -39,46 +46,94 @@
     String getSubscriberId();
 
     /**
+     * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones.
+     */
+    String getSubscriberIdUsingSubId(long subId);
+
+    /**
      * Retrieves the Group Identifier Level1 for GSM phones.
      */
     String getGroupIdLevel1();
 
     /**
+     * Retrieves the Group Identifier Level1 for GSM phones of a subId.
+     */
+    String getGroupIdLevel1UsingSubId(long subId);
+
+    /**
      * Retrieves the serial number of the ICC, if applicable.
      */
     String getIccSerialNumber();
 
     /**
+     * Retrieves the serial number of a given subId.
+     */
+    String getIccSerialNumberUsingSubId(long subId);
+
+    /**
      * Retrieves the phone number string for line 1.
      */
     String getLine1Number();
 
     /**
+     * Retrieves the phone number string for line 1 of a subcription.
+     */
+    String getLine1NumberUsingSubId(long subId);
+
+
+    /**
      * Retrieves the alpha identifier for line 1.
      */
     String getLine1AlphaTag();
 
     /**
+     * Retrieves the alpha identifier for line 1 of a subId.
+     */
+    String getLine1AlphaTagUsingSubId(long subId);
+
+
+    /**
      * Retrieves MSISDN Number.
      */
     String getMsisdn();
 
     /**
+     * Retrieves the Msisdn of a subId.
+     */
+    String getMsisdnUsingSubId(long subId);
+
+    /**
      * Retrieves the voice mail number.
      */
     String getVoiceMailNumber();
 
     /**
+     * Retrieves the voice mail number of a given subId.
+     */
+    String getVoiceMailNumberUsingSubId(long subId);
+
+    /**
      * Retrieves the complete voice mail number.
      */
     String getCompleteVoiceMailNumber();
 
     /**
+     * Retrieves the complete voice mail number for particular subId
+     */
+    String getCompleteVoiceMailNumberUsingSubId(long subId);
+
+    /**
      * Retrieves the alpha identifier associated with the voice mail number.
      */
     String getVoiceMailAlphaTag();
 
     /**
+     * Retrieves the alpha identifier associated with the voice mail number
+     * of a subId.
+     */
+    String getVoiceMailAlphaTagUsingSubId(long subId);
+
+    /**
      * Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
      * @return the IMPI, or null if not present or not loaded
      */
@@ -96,4 +151,38 @@
      *      not present or not loaded
      */
     String[] getIsimImpu();
+
+    /**
+     * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+     * @return IMS Service Table or null if not present or not loaded
+     */
+    String getIsimIst();
+
+    /**
+     * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+     * @return an array of PCSCF strings with one PCSCF per string, or null if
+     *      not present or not loaded
+     */
+    String[] getIsimPcscf();
+
+    /**
+     * TODO: Deprecate and remove this interface. Superceded by getIccsimChallengeResponse.
+     * Returns the response of ISIM Authetification through RIL.
+     * @return the response of ISIM Authetification, or null if
+     *     the Authentification hasn't been successed or isn't present iphonesubinfo.
+     */
+    String getIsimChallengeResponse(String nonce);
+
+    /**
+     * Returns the response of the SIM application on the UICC to authentication
+     * challenge/response algorithm. The data string and challenge response are
+     * Base64 encoded Strings.
+     * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
+     *
+     * @param subId subscription ID to be queried
+     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+     * @param data authentication challenge data
+     * @return challenge response
+     */
+    String getIccSimChallengeResponse(long subId, int appType, String data);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 3e8db06..9e975e9 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -42,6 +42,13 @@
      List<SmsRawData> getAllMessagesFromIccEf(String callingPkg);
 
     /**
+     * Retrieves all messages currently stored on ICC.
+     * @param subId the subId id.
+     * @return list of SmsRawData of all sms on ICC
+     */
+    List<SmsRawData> getAllMessagesFromIccEfUsingSubId(in long subId, String callingPkg);
+
+    /**
      * Update the specified message on the ICC.
      *
      * @param messageIndex record index of message to update
@@ -56,6 +63,21 @@
             in byte[] pdu);
 
     /**
+     * Update the specified message on the ICC.
+     *
+     * @param messageIndex record index of message to update
+     * @param newStatus new message status (STATUS_ON_ICC_READ,
+     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
+     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
+     * @param pdu the raw PDU to store
+     * @param subId the subId id.
+     * @return success or not
+     *
+     */
+     boolean updateMessageOnIccEfUsingSubId(in long subId, String callingPkg,
+             int messageIndex, int newStatus, in byte[] pdu);
+
+    /**
      * Copy a raw SMS PDU to the ICC.
      *
      * @param pdu the raw PDU to store
@@ -67,6 +89,19 @@
     boolean copyMessageToIccEf(String callingPkg, int status, in byte[] pdu, in byte[] smsc);
 
     /**
+     * Copy a raw SMS PDU to the ICC.
+     *
+     * @param pdu the raw PDU to store
+     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
+     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
+     * @param subId the subId id.
+     * @return success or not
+     *
+     */
+    boolean copyMessageToIccEfUsingSubId(in long subId, String callingPkg, int status,
+            in byte[] pdu, in byte[] smsc);
+
+    /**
      * Send a data SMS.
      *
      * @param smsc the SMSC to send the message through, or NULL for the
@@ -93,6 +128,34 @@
             in byte[] data, in PendingIntent sentIntent, in PendingIntent deliveryIntent);
 
     /**
+     * Send a data SMS.
+     *
+     * @param smsc the SMSC to send the message through, or NULL for the
+     *  default SMSC
+     * @param data the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is sucessfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK<code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applicaitons,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param subId the subId id.
+     */
+    void sendDataUsingSubId(long subId, String callingPkg, in String destAddr,
+            in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent,
+            in PendingIntent deliveryIntent);
+
+    /**
      * Send an SMS.
      *
      * @param smsc the SMSC to send the message through, or NULL for the
@@ -119,6 +182,47 @@
             in PendingIntent sentIntent, in PendingIntent deliveryIntent);
 
     /**
+     * Send an SMS.
+     *
+     * @param smsc the SMSC to send the message through, or NULL for the
+     *  default SMSC
+     * @param text the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is sucessfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK<code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param subId the subId on which the SMS has to be sent.
+     */
+    void sendTextUsingSubId(in long subId, String callingPkg, in String destAddr,
+            in String scAddr, in String text, in PendingIntent sentIntent,
+            in PendingIntent deliveryIntent);
+
+    /**
+     * Inject an SMS PDU into the android platform.
+     *
+     * @param pdu is the byte array of pdu to be injected into android application framework
+     * @param format is the format of SMS pdu (android.telephony.SmsMessage.FORMAT_3GPP or
+     * android.telephony.SmsMessage.FORMAT_3GPP2)
+     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is successfully received by the
+     *  android application framework. This intent is broadcasted at
+     *  the same time an SMS received from radio is acknowledged back.
+     */
+    void injectSmsPdu(in byte[] pdu, String format, in PendingIntent receivedIntent);
+
+    /**
      * Send a multi-part text based SMS.
      *
      * @param destinationAddress the address to send the message to
@@ -145,6 +249,34 @@
             in List<PendingIntent> deliveryIntents);
 
     /**
+     * Send a multi-part text based SMS.
+     *
+     * @param destinationAddress the address to send the message to
+     * @param scAddress is the service center address or null to use
+     *   the current default SMSC
+     * @param parts an <code>ArrayList</code> of strings that, in order,
+     *   comprise the original message
+     * @param sentIntents if not null, an <code>ArrayList</code> of
+     *   <code>PendingIntent</code>s (one for each message part) that is
+     *   broadcast when the corresponding message part has been sent.
+     *   The result code will be <code>Activity.RESULT_OK<code> for success,
+     *   or one of these errors:
+     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
+     *   <code>RESULT_ERROR_RADIO_OFF</code>
+     *   <code>RESULT_ERROR_NULL_PDU</code>.
+     * @param deliveryIntents if not null, an <code>ArrayList</code> of
+     *   <code>PendingIntent</code>s (one for each message part) that is
+     *   broadcast when the corresponding message part has been delivered
+     *   to the recipient.  The raw pdu of the status report is in the
+     *   extended data ("pdu").
+     * @param subId the subId on which the SMS has to be sent.
+     */
+    void sendMultipartTextUsingSubId(in long subId, String callingPkg,
+            in String destinationAddress, in String scAddress,
+            in List<String> parts, in List<PendingIntent> sentIntents,
+            in List<PendingIntent> deliveryIntents);
+
+    /**
      * Enable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier. Note that if two different clients enable the same
      * message identifier, they must both disable it for the device to stop
@@ -159,6 +291,21 @@
     boolean enableCellBroadcast(int messageIdentifier);
 
     /**
+     * Enable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier. Note that if two different clients enable the same
+     * message identifier, they must both disable it for the device to stop
+     * receiving those messages.
+     *
+     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be enabled
+     * @return true if successful, false otherwise
+     *
+     * @see #disableCellBroadcast(int)
+     */
+    boolean enableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
+    /**
      * Disable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier. Note that if two different clients enable the same
      * message identifier, they must both disable it for the device to stop
@@ -172,6 +319,21 @@
      */
     boolean disableCellBroadcast(int messageIdentifier);
 
+    /**
+     * Disable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier. Note that if two different clients enable the same
+     * message identifier, they must both disable it for the device to stop
+     * receiving those messages.
+     *
+     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be disabled
+     * @return true if successful, false otherwise
+     *
+     * @see #enableCellBroadcast(int)
+     */
+    boolean disableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
     /*
      * Enable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier range. Note that if two different clients enable
@@ -188,6 +350,23 @@
      */
     boolean enableCellBroadcastRange(int startMessageId, int endMessageId);
 
+    /*
+     * Enable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier range. Note that if two different clients enable
+     * a message identifier range, they must both disable it for the device
+     * to stop receiving those messages.
+     *
+     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be enabled
+     * @return true if successful, false otherwise
+     *
+     * @see #disableCellBroadcastRange(int, int)
+     */
+    boolean enableCellBroadcastRangeUsingSubId(long subId, int startMessageId, int endMessageId);
+
     /**
      * Disable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier range. Note that if two different clients enable
@@ -205,18 +384,52 @@
     boolean disableCellBroadcastRange(int startMessageId, int endMessageId);
 
     /**
+     * Disable reception of cell broadcast (SMS-CB) messages with the given
+     * message identifier range. Note that if two different clients enable
+     * a message identifier range, they must both disable it for the device
+     * to stop receiving those messages.
+     *
+     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+     *   C.R1001-G (3GPP2)
+     * @param subId for which the broadcast has to be disabled
+     * @return true if successful, false otherwise
+     *
+     * @see #enableCellBroadcastRange(int, int, int)
+     */
+    boolean disableCellBroadcastRangeUsingSubId(long subId, int startMessageId,
+            int endMessageId);
+
+    /**
      * Returns the premium SMS send permission for the specified package.
      * Requires system permission.
      */
     int getPremiumSmsPermission(String packageName);
 
     /**
+     * Returns the premium SMS send permission for the specified package.
+     * Requires system permission.
+     */
+    int getPremiumSmsPermissionUsingSubId(long subId, String packageName);
+
+    /**
      * Set the SMS send permission for the specified package.
      * Requires system permission.
      */
     void setPremiumSmsPermission(String packageName, int permission);
 
     /**
+     * Set the SMS send permission for the specified package.
+     * Requires system permission.
+     */
+     /**
+     * Set the SMS send permission for the specified package.
+     * Requires system permission.
+     */
+    void setPremiumSmsPermissionUsingSubId(long subId, String packageName, int permission);
+
+    /**
      * SMS over IMS is supported if IMS is registered and SMS is supported
      * on IMS.
      *
@@ -227,6 +440,23 @@
     boolean isImsSmsSupported();
 
     /**
+     * SMS over IMS is supported if IMS is registered and SMS is supported
+     * on IMS.
+     * @param subId for subId which isImsSmsSupported is queried
+     * @return true if SMS over IMS is supported, false otherwise
+     *
+     * @see #getImsSmsFormat()
+     */
+    boolean isImsSmsSupportedUsingSubId(long subId);
+
+    /*
+     * get user prefered SMS subId
+     * @return subId id
+     */
+    long getPreferredSmsSubscription();
+
+
+    /**
      * Gets SMS format supported on IMS.  SMS over IMS format is
      * either 3GPP or 3GPP2.
      *
@@ -237,4 +467,25 @@
      * @see #isImsSmsSupported()
      */
     String getImsSmsFormat();
+
+    /**
+     * Gets SMS format supported on IMS.  SMS over IMS format is
+     * either 3GPP or 3GPP2.
+     * @param subId for subId which getImsSmsFormat is queried
+     * @return android.telephony.SmsMessage.FORMAT_3GPP,
+     *         android.telephony.SmsMessage.FORMAT_3GPP2
+     *      or android.telephony.SmsMessage.FORMAT_UNKNOWN
+     *
+     * @see #isImsSmsSupported()
+     */
+    String getImsSmsFormatUsingSubId(long subId);
+
+
+
+
+    /*
+     * Get SMS prompt property,  enabled or not
+     * @return true if enabled, false otherwise
+     */
+    boolean isSMSPromptEnabled();
 }
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
new file mode 100755
index 0000000..6021ccf
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -0,0 +1,153 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.telephony;
+
+import android.app.PendingIntent;
+import android.telephony.SubInfoRecord;
+
+interface ISub {
+    /**
+     * Get the SubInfoRecord according to an index
+     * @param context Context provided by caller
+     * @param subId The unique SubInfoRecord index in database
+     * @return SubInfoRecord, maybe null
+     */
+    SubInfoRecord getSubInfoUsingSubId(long subId);
+
+    /**
+     * Get the SubInfoRecord according to an IccId
+     * @param context Context provided by caller
+     * @param iccId the IccId of SIM card
+     * @return SubInfoRecord, maybe null
+     */
+    List<SubInfoRecord> getSubInfoUsingIccId(String iccId);
+
+    /**
+     * Get the SubInfoRecord according to slotId
+     * @param context Context provided by caller
+     * @param slotId the slot which the SIM is inserted
+     * @return SubInfoRecord, maybe null
+     */
+    List<SubInfoRecord> getSubInfoUsingSlotId(int slotId);
+
+    /**
+     * Get all the SubInfoRecord(s) in subinfo database
+     * @param context Context provided by caller
+     * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+     */
+    List<SubInfoRecord> getAllSubInfoList();
+
+    /**
+     * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+     * @param context Context provided by caller
+     * @return Array list of currently inserted SubInfoRecord(s)
+     */
+    List<SubInfoRecord> getActivatedSubInfoList();
+
+    /**
+     * Get the SUB count of all SUB(s) in subinfo database
+     * @param context Context provided by caller
+     * @return all SIM count in database, include what was inserted before
+     */
+    int getAllSubInfoCount();
+
+    /**
+     * Add a new SubInfoRecord to subinfo database if needed
+     * @param context Context provided by caller
+     * @param iccId the IccId of the SIM card
+     * @param slotId the slot which the SIM is inserted
+     * @return the URL of the newly created row or the updated row
+     */
+    int addSubInfoRecord(String iccId, int slotId);
+
+    /**
+     * Set SIM color by simInfo index
+     * @param context Context provided by caller
+     * @param color the color of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setColor(int color, long subId);
+
+    /**
+     * Set display name by simInfo index
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDisplayName(String displayName, long subId);
+
+    /**
+     * Set display name by simInfo index with name source
+     * @param context Context provided by caller
+     * @param displayName the display name of SIM card
+     * @param subId the unique SubInfoRecord index in database
+     * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+     * @return the number of records updated
+     */
+    int setDisplayNameUsingSrc(String displayName, long subId, long nameSource);
+
+    /**
+     * Set phone number by subId
+     * @param context Context provided by caller
+     * @param number the phone number of the SIM
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDispalyNumber(String number, long subId);
+
+    /**
+     * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+     * @param context Context provided by caller
+     * @param format the display format of phone number
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDisplayNumberFormat(int format, long subId);
+
+    /**
+     * Set data roaming by simInfo index
+     * @param context Context provided by caller
+     * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    int setDataRoaming(int roaming, long subId);
+
+    int getSlotId(long subId);
+
+    long[] getSubId(int slotId);
+
+    long getDefaultSubId();
+
+    int clearSubInfo();
+
+    int getPhoneId(long subId);
+
+    /**
+     * Get the default data subscription
+     * @return Id of the data subscription
+     */
+    long getDefaultDataSubId();
+
+    void setDefaultDataSubId(long subId);
+
+    long getDefaultVoiceSubId();
+
+    void setDefaultVoiceSubId(long subId);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index acaa8de..407da87 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,14 +16,11 @@
 
 package com.android.internal.telephony;
 
-import android.content.ComponentName;
 import android.os.Bundle;
-import android.telephony.CellInfo;
+import java.util.List;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.CellInfo;
 
-import java.util.List;
-
-import java.util.List;
 
 /**
  * Interface used to interact with the phone.  Mostly this is used by the
@@ -56,6 +53,13 @@
     boolean endCall();
 
     /**
+     * End call on particular subId or go to the Home screen
+     * @param subId user preferred subId.
+     * @return whether it hung up
+     */
+    boolean endCallUsingSubId(long subId);
+
+    /**
      * Answer the currently-ringing call.
      *
      * If there's already a current active call, that call will be
@@ -92,6 +96,23 @@
     boolean isOffhook();
 
     /**
+     * Check if a particular subId has an active or holding call
+     *
+     * @param subId user preferred subId.
+     * @return true if the phone state is OFFHOOK.
+     */
+    boolean isOffhookUsingSubId(long subId);
+
+    /**
+     * Check if an incoming phone call is ringing or call waiting
+     * on a particular subId.
+     *
+     * @param subId user preferred subId.
+     * @return true if the phone state is RINGING.
+     */
+    boolean isRingingUsingSubId(long subId);
+
+    /**
      * Check if an incoming phone call is ringing or call waiting.
      * @return true if the phone state is RINGING.
      */
@@ -104,12 +125,27 @@
     boolean isIdle();
 
     /**
+     * Check if the phone is idle on a particular subId.
+     *
+     * @param subId user preferred subId.
+     * @return true if the phone state is IDLE.
+     */
+    boolean isIdleUsingSubId(long subId);
+
+    /**
      * Check to see if the radio is on or not.
      * @return returns true if the radio is on.
      */
     boolean isRadioOn();
 
     /**
+     * Check to see if the radio is on or not on particular subId.
+     * @param subId user preferred subId.
+     * @return returns true if the radio is on.
+     */
+    boolean isRadioOnUsingSubId(long subId);
+
+    /**
      * Check if the SIM pin lock is enabled.
      * @return true if the SIM pin lock is enabled.
      */
@@ -128,6 +164,15 @@
     boolean supplyPin(String pin);
 
     /**
+     * Supply a pin to unlock the SIM for particular subId.
+     * Blocks until a result is determined.
+     * @param pin The pin to check.
+     * @param subId user preferred subId.
+     * @return whether the operation was a success.
+     */
+    boolean supplyPinUsingSubId(long subId, String pin);
+
+    /**
      * Supply puk to unlock the SIM and set SIM pin to new pin.
      *  Blocks until a result is determined.
      * @param puk The puk to check.
@@ -137,6 +182,16 @@
     boolean supplyPuk(String puk, String pin);
 
     /**
+     * Supply puk to unlock the SIM and set SIM pin to new pin.
+     *  Blocks until a result is determined.
+     * @param puk The puk to check.
+     *        pin The new pin to be set in SIM
+     * @param subId user preferred subId.
+     * @return whether the operation was a success.
+     */
+    boolean supplyPukUsingSubId(long subId, String puk, String pin);
+
+    /**
      * Supply a pin to unlock the SIM.  Blocks until a result is determined.
      * Returns a specific success/error code.
      * @param pin The pin to check.
@@ -146,6 +201,15 @@
     int[] supplyPinReportResult(String pin);
 
     /**
+     * Supply a pin to unlock the SIM.  Blocks until a result is determined.
+     * Returns a specific success/error code.
+     * @param pin The pin to check.
+     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+     *         retValue[1] = number of attempts remaining if known otherwise -1
+     */
+    int[] supplyPinReportResultUsingSubId(long subId, String pin);
+
+    /**
      * Supply puk to unlock the SIM and set SIM pin to new pin.
      * Blocks until a result is determined.
      * Returns a specific success/error code
@@ -157,6 +221,17 @@
     int[] supplyPukReportResult(String puk, String pin);
 
     /**
+     * Supply puk to unlock the SIM and set SIM pin to new pin.
+     * Blocks until a result is determined.
+     * Returns a specific success/error code
+     * @param puk The puk to check
+     *        pin The pin to check.
+     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+     *         retValue[1] = number of attempts remaining if known otherwise -1
+     */
+    int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin);
+
+    /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
      * without SEND (so <code>dial</code> is not appropriate).
      *
@@ -166,16 +241,38 @@
     boolean handlePinMmi(String dialString);
 
     /**
+     * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
+     * without SEND (so <code>dial</code> is not appropriate) for
+     * a particular subId.
+     * @param dialString the MMI command to be executed.
+     * @param subId user preferred subId.
+     * @return true if MMI command is executed.
+     */
+    boolean handlePinMmiUsingSubId(long subId, String dialString);
+
+    /**
      * Toggles the radio on or off.
      */
     void toggleRadioOnOff();
 
     /**
+     * Toggles the radio on or off on particular subId.
+     * @param subId user preferred subId.
+     */
+    void toggleRadioOnOffUsingSubId(long subId);
+
+    /**
      * Set the radio to on or off
      */
     boolean setRadio(boolean turnOn);
 
     /**
+     * Set the radio to on or off on particular subId.
+     * @param subId user preferred subId.
+     */
+    boolean setRadioUsingSubId(long subId, boolean turnOn);
+
+    /**
      * Set the radio to on or off unconditionally
      */
     boolean setRadioPower(boolean turnOn);
@@ -186,16 +283,35 @@
     void updateServiceLocation();
 
     /**
+     * Request to update location information for a subscrition in service state
+     * @param subId user preferred subId.
+     */
+    void updateServiceLocationUsingSubId(long subId);
+
+    /**
      * Enable location update notifications.
      */
     void enableLocationUpdates();
 
     /**
+     * Enable location update notifications.
+     * @param subId user preferred subId.
+     */
+    void enableLocationUpdatesUsingSubId(long subId);
+
+    /**
      * Disable location update notifications.
      */
     void disableLocationUpdates();
 
     /**
+     * Disable location update notifications.
+     * @param subId user preferred subId.
+     */
+    void disableLocationUpdatesUsingSubId(long subId);
+
+
+    /**
      * Enable a specific APN type.
      */
     int enableApnType(String type);
@@ -206,6 +322,16 @@
     int disableApnType(String type);
 
     /**
+     * Enable a specific APN type with subscription.
+     */
+    int enableApnTypeUsingSub(long subId, String type);
+
+    /**
+     * Disable a specific APN type with subscription.
+     */
+    int disableApnTypeUsingSub(long subId, String type);
+
+    /**
      * Allow mobile data connections.
      */
     boolean enableDataConnectivity();
@@ -228,6 +354,12 @@
     List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
 
      int getCallState();
+
+    /**
+     * Returns the call state for a subId.
+     */
+     int getCallStateUsingSubId(long subId);
+
      int getDataActivity();
      int getDataState();
 
@@ -239,11 +371,25 @@
     int getActivePhoneType();
 
     /**
+     * Returns the current active phone type as integer for particular subId.
+     * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
+     * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
+     * @param subId user preferred subId.
+     */
+    int getActivePhoneTypeUsingSubId(long subId);
+
+    /**
      * Returns the CDMA ERI icon index to display
      */
     int getCdmaEriIconIndex();
 
     /**
+     * Returns the CDMA ERI icon index to display on particular subId.
+     * @param subId user preferred subId.
+     */
+    int getCdmaEriIconIndexUsingSubId(long subId);
+
+    /**
      * Returns the CDMA ERI icon mode,
      * 0 - ON
      * 1 - FLASHING
@@ -251,11 +397,25 @@
     int getCdmaEriIconMode();
 
     /**
+     * Returns the CDMA ERI icon mode on particular subId,
+     * 0 - ON
+     * 1 - FLASHING
+     * @param subId user preferred subId.
+     */
+    int getCdmaEriIconModeUsingSubId(long subId);
+
+    /**
      * Returns the CDMA ERI text,
      */
     String getCdmaEriText();
 
     /**
+     * Returns the CDMA ERI text for particular subId,
+     * @param subId user preferred subId.
+     */
+    String getCdmaEriTextUsingSubId(long subId);
+
+    /**
      * Returns true if OTA service provisioning needs to run.
      * Only relevant on some technologies, others will always
      * return false.
@@ -268,26 +428,61 @@
     int getVoiceMessageCount();
 
     /**
+     * Returns the unread count of voicemails for a subId.
+     * @param subId user preferred subId.
+     * Returns the unread count of voicemails
+     */
+    int getVoiceMessageCountUsingSubId(long subId);
+
+    /**
       * Returns the network type for data transmission
       */
     int getNetworkType();
 
     /**
+     * Returns the network type of a subId.
+     * @param subId user preferred subId.
+     * Returns the network type
+     */
+    int getNetworkTypeUsingSubId(long subId);
+
+    /**
       * Returns the network type for data transmission
       */
     int getDataNetworkType();
 
     /**
+      * Returns the data network type of a subId
+      * @param subId user preferred subId.
+      * Returns the network type
+      */
+    int getDataNetworkTypeUsingSubId(long subId);
+
+    /**
       * Returns the network type for voice
       */
     int getVoiceNetworkType();
 
     /**
+      * Returns the voice network type of a subId
+      * @param subId user preferred subId.
+      * Returns the network type
+      */
+    int getVoiceNetworkTypeUsingSubId(long subId);
+
+    /**
      * Return true if an ICC card is present
      */
     boolean hasIccCard();
 
     /**
+     * Return true if an ICC card is present for a subId.
+     * @param slotId user preferred slotId.
+     * Return true if an ICC card is present
+     */
+    boolean hasIccCardUsingSlotId(long slotId);
+
+    /**
      * Return if the current radio is LTE on CDMA. This
      * is a tri-state return value as for a period of time
      * the mode may be unknown.
@@ -298,6 +493,16 @@
     int getLteOnCdmaMode();
 
     /**
+     * Return if the current radio is LTE on CDMA. This
+     * is a tri-state return value as for a period of time
+     * the mode may be unknown.
+     *
+     * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
+     * or {@link PHone#LTE_ON_CDMA_TRUE}
+     */
+    int getLteOnCdmaModeUsingSubId(long subId);
+
+    /**
      * Returns the all observed cell information of the device.
      */
     List<CellInfo> getAllCellInfo();
@@ -308,6 +513,12 @@
     void setCellInfoListRate(int rateInMillis);
 
     /**
+     * get default sim
+     * @return sim id
+     */
+    int getDefaultSim();
+
+    /**
      * Opens a logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -428,4 +639,16 @@
      * @return true on enabled
      */
     boolean getDataEnabled();
+
+    /**
+     * Get P-CSCF address from PCO after data connection is established or modified.
+     */
+    String[] getPcscfAddress();
+
+    /**
+     * Set IMS registration state
+     */
+    void setImsRegistrationState(boolean registered);
+
 }
+
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index b104c11..fd2d1c7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -24,22 +24,36 @@
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
 import com.android.internal.telephony.IPhoneStateListener;
 
 interface ITelephonyRegistry {
     void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
-
+    void listenUsingSubId(in long subId, String pkg, IPhoneStateListener callback, int events,
+            boolean notifyNow);
     void notifyCallState(int state, String incomingNumber);
+    void notifyCallStateUsingSubId(in long subId, int state, String incomingNumber);
     void notifyServiceState(in ServiceState state);
+    void notifyServiceStateUsingSubId(in long subId, in ServiceState state);
     void notifySignalStrength(in SignalStrength signalStrength);
+    void notifySignalStrengthUsingSubId(in long subId, in SignalStrength signalStrength);
     void notifyMessageWaitingChanged(boolean mwi);
+    void notifyMessageWaitingChangedUsingSubId(in long subId, boolean mwi);
     void notifyCallForwardingChanged(boolean cfi);
+    void notifyCallForwardingChangedUsingSubId(in long subId, boolean cfi);
     void notifyDataActivity(int state);
+    void notifyDataActivityUsingSubId(in long subId, int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, in LinkProperties linkProperties,
             in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
+    void notifyDataConnectionUsingSubId(long subId, int state, boolean isDataConnectivityPossible,
+            String reason, String apn, String apnType, in LinkProperties linkProperties,
+            in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
     void notifyDataConnectionFailed(String reason, String apnType);
+    void notifyDataConnectionFailedUsingSubId(long subId, String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
+    void notifyCellLocationUsingSubId(in long subId, in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
     void notifyCellInfo(in List<CellInfo> cellInfo);
     void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
@@ -47,5 +61,7 @@
     void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
     void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
             String failCause);
+    void notifyCellInfoUsingSubId(in long subId, in List<CellInfo> cellInfo);
     void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
+    void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 08f4379..aecf955 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -58,6 +58,7 @@
     public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
     public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
     public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE;
+    public static final int PHONE_TYPE_IMS = RILConstants.IMS_PHONE;
 
     // Modes for LTE_ON_CDMA
     public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN;
@@ -133,4 +134,55 @@
     /** APN type for IA Initial Attach APN */
     public static final String APN_TYPE_IA = "ia";
 
+    // FIXME: This looks to be used as default phoneId, rename
+    // or use SubscriptionManager.DEFAULT_SUB_ID
+    public static final int DEFAULT_SUBSCRIPTION = 0;
+
+    // FIXME: This looks to be used as invalid phoneId, rename
+    // or use SubscriptionManager.INVALID_SUB_ID
+    public static final int INVALID_SUBSCRIPTION = -1;
+
+    public static final int RIL_CARD_MAX_APPS    = 8;
+
+    public static final int DEFAULT_CARD_INDEX   = 0;
+
+    public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
+
+    public static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
+
+    public static final int MAX_PHONE_COUNT_TRI_SIM = 3;
+
+    public static final String SUBSCRIPTION_KEY  = "subscription";
+
+    public static final String SLOT_KEY  = "slot";
+
+    public static final String SUB_SETTING  = "subSettings";
+
+    public static final int SUB1 = 0;
+    public static final int SUB2 = 1;
+    public static final int SUB3 = 2;
+
+    public static final int EVENT_SUBSCRIPTION_ACTIVATED   = 500;
+    public static final int EVENT_SUBSCRIPTION_DEACTIVATED = 501;
+
+    // TODO: Remove these constants and use an int instead.
+    public static final int SIM_ID_1 = 0;
+    public static final int SIM_ID_2 = 1;
+    public static final int SIM_ID_3 = 2;
+    public static final int SIM_ID_4 = 3;
+
+    // ICC SIM Application Types
+    // TODO: Replace the IccCardApplicationStatus.AppType enums with these constants
+    public static final int APPTYPE_UNKNOWN = 0;
+    public static final int APPTYPE_SIM = 1;
+    public static final int APPTYPE_USIM = 2;
+    public static final int APPTYPE_RUIM = 3;
+    public static final int APPTYPE_CSIM = 4;
+    public static final int APPTYPE_ISIM = 5;
+
+    public enum CardUnavailableReason {
+        REASON_CARD_REMOVED,
+        REASON_RADIO_UNAVAILABLE,
+        REASON_SIM_REFRESH_RESET
+    };
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 815211c..0271d0a 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -57,6 +57,7 @@
                                                  retries needed */
     int MISSING_RESOURCE = 16;                /* no logical channel available */
     int NO_SUCH_ELEMENT = 17;                 /* application not found on SIM */
+    int SUBSCRIPTION_NOT_SUPPORTED = 26;      /* Subscription not supported */
 
     /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
     int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -85,6 +86,7 @@
     int CDMA_PHONE = 2;
     int SIP_PHONE  = 3;
     int THIRD_PARTY_PHONE = 4;
+    int IMS_PHONE = 5;
 
     int LTE_ON_CDMA_UNKNOWN = -1;
     int LTE_ON_CDMA_FALSE = 0;
@@ -282,6 +284,11 @@
     int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
     int RIL_REQUEST_NV_RESET_CONFIG = 121;
     int RIL_REQUEST_SET_RADIO_MODE = 122;
+    int RIL_REQUEST_DATA_IDLE = 123;
+    int RIL_REQUEST_SET_UICC_SUBSCRIPTION = 124;
+    int RIL_REQUEST_ALLOW_DATA = 125;
+    int RIL_REQUEST_GET_HARDWARE_CONFIG = 126;
+    int RIL_REQUEST_ICC_SIM_AUTHENTICATION = 127;
 
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
@@ -322,4 +329,7 @@
     int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035;
     int RIL_UNSOL_CELL_INFO_LIST = 1036;
     int RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037;
+    int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038;
+    int RIL_UNSOL_SRVCC_STATE_NOTIFY = 1039;
+    int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040;
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 9ad2d42..5954947 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import android.content.Intent;
+
 /**
  * The intents that the telephony services broadcast.
  *
@@ -48,7 +50,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -69,7 +71,7 @@
      *
      * <p class="note">
      * Requires no permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -88,7 +90,7 @@
      *
      * <p class="note">
      * Requires no permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -114,7 +116,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -136,7 +138,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -176,7 +178,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -207,7 +209,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -225,7 +227,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -243,7 +245,7 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
-     * 
+     *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -315,4 +317,85 @@
     public static final String EXTRA_PLMN       = "plmn";
     public static final String EXTRA_SHOW_SPN   = "showSpn";
     public static final String EXTRA_SPN        = "spn";
+
+    /**
+     * <p>Broadcast Action: It indicates one column of a siminfo record has been changed
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>columnName</em> - The siminfo column that is updated.</li>
+     *   <li><em>stringContent</em> - The string value of the updated column.</li>
+     *   <li><em>intContent</em> - The int value of the updated column.</li>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SIMINFO_CONTENT_CHANGE
+            = "android.intent.action.ACTION_SIMINFO_CONTENT_CHANGE";
+
+    /**
+     * <p>Broadcast Action: It indicates one column of a subinfo record has been changed
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li><em>columnName</em> - The siminfo column that is updated.</li>
+     *   <li><em>stringContent</em> - The string value of the updated column.</li>
+     *   <li><em>intContent</em> - The int value of the updated column.</li>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SUBINFO_CONTENT_CHANGE
+            = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE";
+
+    /**
+     * <p>Broadcast Action: It indicates siminfo update is completed when SIM inserted state change
+     * The intent will have the following extra values:</p>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SIMINFO_UPDATED
+            = "android.intent.action.ACTION_SIMINFO_UPDATED";
+
+    /**
+     * <p>Broadcast Action: It indicates subinfo record update is completed
+     * when SIM inserted state change
+     * The intent will have the following extra values:</p>
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_SUBINFO_RECORD_UPDATED
+            = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED";
+
+    public static final String EXTRA_COLUMN_NAME = "columnName";
+    public static final String EXTRA_INT_CONTENT = "intContent";
+    public static final String EXTRA_STRING_CONTENT = "stringContent";
+
+    /**
+     * Broadcast Action: The default subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Broadcast Action: The default data subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current data default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
+
+    /**
+     * Broadcast Action: The default voice subscription has changed.  This has the following
+     * extra values:</p>
+     * <ul>
+     *   <li><em>subscription</em> - A int, the current voice default subscription.</li>
+     * </ul>
+     */
+    public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED
+            = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index f95e081..5ec4247 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -187,4 +187,26 @@
      * Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing.
      */
     static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz";
+
+     /**
+     * Property to set multi sim feature.
+     * Type:  String(dsds, dsda)
+     */
+    static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config";
+
+    /**
+     * Property to store default subscription.
+     */
+    static final String PROPERTY_DEFAULT_SUBSCRIPTION = "persist.radio.default.sub";
+
+    /**
+     * Property to enable MMS Mode.
+     * Type: string ( default = silent, enable to = prompt )
+     */
+    static final String PROPERTY_MMS_TRANSACTION = "mms.transaction";
+
+    /**
+     * Set to the sim count.
+     */
+    static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count";
 }
diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk
new file mode 100644
index 0000000..7e5911d
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
new file mode 100644
index 0000000..a92b5d8
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.camera2.cameratoo">
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application android:label="CameraToo">
+        <activity
+            android:name=".CameraTooActivity"
+            android:screenOrientation="portrait">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
new file mode 100644
index 0000000..f93f177
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+    Copyright (C) 2014 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/mainSurfaceView"
+    android:layout_height="fill_parent"
+    android:layout_width="fill_parent"
+    android:onClick="onClickOnSurfaceView" />
diff --git a/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
new file mode 100644
index 0000000..c630bad
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
@@ -0,0 +1,437 @@
+/*
+ * 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.example.android.camera2.cameratoo;
+
+import android.app.Activity;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Size;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A basic demonstration of how to write a point-and-shoot camera app against the new
+ * android.hardware.camera2 API.
+ */
+public class CameraTooActivity extends Activity {
+    /** Output files will be saved as /sdcard/Pictures/cameratoo*.jpg */
+    static final String CAPTURE_FILENAME_PREFIX = "cameratoo";
+    /** Tag to distinguish log prints. */
+    static final String TAG = "CameraToo";
+
+    /** An additional thread for running tasks that shouldn't block the UI. */
+    HandlerThread mBackgroundThread;
+    /** Handler for running tasks in the background. */
+    Handler mBackgroundHandler;
+    /** Handler for running tasks on the UI thread. */
+    Handler mForegroundHandler;
+    /** View for displaying the camera preview. */
+    SurfaceView mSurfaceView;
+    /** Used to retrieve the captured image when the user takes a snapshot. */
+    ImageReader mCaptureBuffer;
+    /** Handle to the Android camera services. */
+    CameraManager mCameraManager;
+    /** The specific camera device that we're using. */
+    CameraDevice mCamera;
+    /** Our image capture session. */
+    CameraCaptureSession mCaptureSession;
+
+    /**
+     * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+     * width and height are at least as large as the respective requested values.
+     * @param choices The list of sizes that the camera supports for the intended output class
+     * @param width The minimum desired width
+     * @param height The minimum desired height
+     * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+     */
+    static Size chooseBigEnoughSize(Size[] choices, int width, int height) {
+        // Collect the supported resolutions that are at least as big as the preview Surface
+        List<Size> bigEnough = new ArrayList<Size>();
+        for (Size option : choices) {
+            if (option.getWidth() >= width && option.getHeight() >= height) {
+                bigEnough.add(option);
+            }
+        }
+
+        // Pick the smallest of those, assuming we found any
+        if (bigEnough.size() > 0) {
+            return Collections.min(bigEnough, new CompareSizesByArea());
+        } else {
+            Log.e(TAG, "Couldn't find any suitable preview size");
+            return choices[0];
+        }
+    }
+
+    /**
+     * Compares two {@code Size}s based on their areas.
+     */
+    static class CompareSizesByArea implements Comparator<Size> {
+        @Override
+        public int compare(Size lhs, Size rhs) {
+            // We cast here to ensure the multiplications won't overflow
+            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+                    (long) rhs.getWidth() * rhs.getHeight());
+        }
+    }
+
+    /**
+     * Called when our {@code Activity} gains focus. <p>Starts initializing the camera.</p>
+     */
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // Start a background thread to manage camera requests
+        mBackgroundThread = new HandlerThread("background");
+        mBackgroundThread.start();
+        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+        mForegroundHandler = new Handler(getMainLooper());
+
+        mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
+
+        // Inflate the SurfaceView, set it as the main layout, and attach a listener
+        View layout = getLayoutInflater().inflate(R.layout.mainactivity, null);
+        mSurfaceView = (SurfaceView) layout.findViewById(R.id.mainSurfaceView);
+        mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
+        setContentView(mSurfaceView);
+
+        // Control flow continues in mSurfaceHolderCallback.surfaceChanged()
+    }
+
+    /**
+     * Called when our {@code Activity} loses focus. <p>Tears everything back down.</p>
+     */
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        try {
+            // Ensure SurfaceHolderCallback#surfaceChanged() will run again if the user returns
+            mSurfaceView.getHolder().setFixedSize(/*width*/0, /*height*/0);
+
+            // Cancel any stale preview jobs
+            if (mCaptureSession != null) {
+                mCaptureSession.close();
+                mCaptureSession = null;
+            }
+        } finally {
+            if (mCamera != null) {
+                mCamera.close();
+                mCamera = null;
+            }
+        }
+
+        // Finish processing posted messages, then join on the handling thread
+        mBackgroundThread.quitSafely();
+        try {
+            mBackgroundThread.join();
+        } catch (InterruptedException ex) {
+            Log.e(TAG, "Background worker thread was interrupted while joined", ex);
+        }
+
+        // Close the ImageReader now that the background thread has stopped
+        if (mCaptureBuffer != null) mCaptureBuffer.close();
+    }
+
+    /**
+     * Called when the user clicks on our {@code SurfaceView}, which has ID {@code mainSurfaceView}
+     * as defined in the {@code mainactivity.xml} layout file. <p>Captures a full-resolution image
+     * and saves it to permanent storage.</p>
+     */
+    public void onClickOnSurfaceView(View v) {
+        if (mCaptureSession != null) {
+            try {
+                CaptureRequest.Builder requester =
+                        mCamera.createCaptureRequest(mCamera.TEMPLATE_STILL_CAPTURE);
+                requester.addTarget(mCaptureBuffer.getSurface());
+                try {
+                    // This handler can be null because we aren't actually attaching any callback
+                    mCaptureSession.capture(requester.build(), /*listener*/null, /*handler*/null);
+                } catch (CameraAccessException ex) {
+                    Log.e(TAG, "Failed to file actual capture request", ex);
+                }
+            } catch (CameraAccessException ex) {
+                Log.e(TAG, "Failed to build actual capture request", ex);
+            }
+        } else {
+            Log.e(TAG, "User attempted to perform a capture outside our session");
+        }
+
+        // Control flow continues in mImageCaptureListener.onImageAvailable()
+    }
+
+    /**
+     * Callbacks invoked upon state changes in our {@code SurfaceView}.
+     */
+    final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+        /** The camera device to use, or null if we haven't yet set a fixed surface size. */
+        private String mCameraId;
+
+        /** Whether we received a change callback after setting our fixed surface size. */
+        private boolean mGotSecondCallback;
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            // This is called every time the surface returns to the foreground
+            Log.i(TAG, "Surface created");
+            mCameraId = null;
+            mGotSecondCallback = false;
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            Log.i(TAG, "Surface destroyed");
+            holder.removeCallback(this);
+            // We don't stop receiving callbacks forever because onResume() will reattach us
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            // On the first invocation, width and height were automatically set to the view's size
+            if (mCameraId == null) {
+                // Find the device's back-facing camera and set the destination buffer sizes
+                try {
+                    for (String cameraId : mCameraManager.getCameraIdList()) {
+                        CameraCharacteristics cameraCharacteristics =
+                                mCameraManager.getCameraCharacteristics(cameraId);
+                        if (cameraCharacteristics.get(cameraCharacteristics.LENS_FACING) ==
+                                CameraCharacteristics.LENS_FACING_BACK) {
+                            Log.i(TAG, "Found a back-facing camera");
+                            StreamConfigurationMap info = cameraCharacteristics
+                                    .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+                            // Bigger is better when it comes to saving our image
+                            Size largestSize = Collections.max(
+                                    Arrays.asList(info.getOutputSizes(ImageFormat.JPEG)),
+                                    new CompareSizesByArea());
+
+                            // Prepare an ImageReader in case the user wants to capture images
+                            Log.i(TAG, "Capture size: " + largestSize);
+                            mCaptureBuffer = ImageReader.newInstance(largestSize.getWidth(),
+                                    largestSize.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
+                            mCaptureBuffer.setOnImageAvailableListener(
+                                    mImageCaptureListener, mBackgroundHandler);
+
+                            // Danger, W.R.! Attempting to use too large a preview size could
+                            // exceed the camera bus' bandwidth limitation, resulting in
+                            // gorgeous previews but the storage of garbage capture data.
+                            Log.i(TAG, "SurfaceView size: " +
+                                    mSurfaceView.getWidth() + 'x' + mSurfaceView.getHeight());
+                            Size optimalSize = chooseBigEnoughSize(
+                                    info.getOutputSizes(SurfaceHolder.class), width, height);
+
+                            // Set the SurfaceHolder to use the camera's largest supported size
+                            Log.i(TAG, "Preview size: " + optimalSize);
+                            SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
+                            surfaceHolder.setFixedSize(optimalSize.getWidth(),
+                                    optimalSize.getHeight());
+
+                            mCameraId = cameraId;
+                            return;
+
+                            // Control flow continues with this method one more time
+                            // (since we just changed our own size)
+                        }
+                    }
+                } catch (CameraAccessException ex) {
+                    Log.e(TAG, "Unable to list cameras", ex);
+                }
+
+                Log.e(TAG, "Didn't find any back-facing cameras");
+            // This is the second time the method is being invoked: our size change is complete
+            } else if (!mGotSecondCallback) {
+                if (mCamera != null) {
+                    Log.e(TAG, "Aborting camera open because it hadn't been closed");
+                    return;
+                }
+
+                // Open the camera device
+                try {
+                    mCameraManager.openCamera(mCameraId, mCameraStateListener,
+                            mBackgroundHandler);
+                } catch (CameraAccessException ex) {
+                    Log.e(TAG, "Failed to configure output surface", ex);
+                }
+                mGotSecondCallback = true;
+
+                // Control flow continues in mCameraStateListener.onOpened()
+            }
+        }};
+
+    /**
+     * Calledbacks invoked upon state changes in our {@code CameraDevice}. <p>These are run on
+     * {@code mBackgroundThread}.</p>
+     */
+    final CameraDevice.StateListener mCameraStateListener =
+            new CameraDevice.StateListener() {
+        @Override
+        public void onOpened(CameraDevice camera) {
+            Log.i(TAG, "Successfully opened camera");
+            mCamera = camera;
+            try {
+                List<Surface> outputs = Arrays.asList(
+                        mSurfaceView.getHolder().getSurface(), mCaptureBuffer.getSurface());
+                camera.createCaptureSession(outputs, mCaptureSessionListener,
+                        mBackgroundHandler);
+            } catch (CameraAccessException ex) {
+                Log.e(TAG, "Failed to create a capture session", ex);
+            }
+
+            // Control flow continues in mCaptureSessionListener.onConfigured()
+        }
+
+        @Override
+        public void onDisconnected(CameraDevice camera) {
+            Log.e(TAG, "Camera was disconnected");
+        }
+
+        @Override
+        public void onError(CameraDevice camera, int error) {
+            Log.e(TAG, "State error on device '" + camera.getId() + "': code " + error);
+        }};
+
+    /**
+     * Callbacks invoked upon state changes in our {@code CameraCaptureSession}. <p>These are run on
+     * {@code mBackgroundThread}.</p>
+     */
+    final CameraCaptureSession.StateListener mCaptureSessionListener =
+            new CameraCaptureSession.StateListener() {
+        @Override
+        public void onConfigured(CameraCaptureSession session) {
+            Log.i(TAG, "Finished configuring camera outputs");
+            mCaptureSession = session;
+
+            SurfaceHolder holder = mSurfaceView.getHolder();
+            if (holder != null) {
+                try {
+                    // Build a request for preview footage
+                    CaptureRequest.Builder requestBuilder =
+                            mCamera.createCaptureRequest(mCamera.TEMPLATE_PREVIEW);
+                    requestBuilder.addTarget(holder.getSurface());
+                    CaptureRequest previewRequest = requestBuilder.build();
+
+                    // Start displaying preview images
+                    try {
+                        session.setRepeatingRequest(previewRequest, /*listener*/null,
+                                /*handler*/null);
+                    } catch (CameraAccessException ex) {
+                        Log.e(TAG, "Failed to make repeating preview request", ex);
+                    }
+                } catch (CameraAccessException ex) {
+                    Log.e(TAG, "Failed to build preview request", ex);
+                }
+            }
+            else {
+                Log.e(TAG, "Holder didn't exist when trying to formulate preview request");
+            }
+        }
+
+        @Override
+        public void onClosed(CameraCaptureSession session) {
+            mCaptureSession = null;
+        }
+
+        @Override
+        public void onConfigureFailed(CameraCaptureSession session) {
+            Log.e(TAG, "Configuration error on device '" + mCamera.getId());
+        }};
+
+    /**
+     * Callback invoked when we've received a JPEG image from the camera.
+     */
+    final ImageReader.OnImageAvailableListener mImageCaptureListener =
+            new ImageReader.OnImageAvailableListener() {
+        @Override
+        public void onImageAvailable(ImageReader reader) {
+            // Save the image once we get a chance
+            mBackgroundHandler.post(new CapturedImageSaver(reader.acquireNextImage()));
+
+            // Control flow continues in CapturedImageSaver#run()
+        }};
+
+    /**
+     * Deferred processor responsible for saving snapshots to disk. <p>This is run on
+     * {@code mBackgroundThread}.</p>
+     */
+    static class CapturedImageSaver implements Runnable {
+        /** The image to save. */
+        private Image mCapture;
+
+        public CapturedImageSaver(Image capture) {
+            mCapture = capture;
+        }
+
+        @Override
+        public void run() {
+            try {
+                // Choose an unused filename under the Pictures/ directory
+                File file = File.createTempFile(CAPTURE_FILENAME_PREFIX, ".jpg",
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_PICTURES));
+                try (FileOutputStream ostream = new FileOutputStream(file)) {
+                    Log.i(TAG, "Retrieved image is" +
+                            (mCapture.getFormat() == ImageFormat.JPEG ? "" : "n't") + " a JPEG");
+                    ByteBuffer buffer = mCapture.getPlanes()[0].getBuffer();
+                    Log.i(TAG, "Captured image size: " +
+                            mCapture.getWidth() + 'x' + mCapture.getHeight());
+
+                    // Write the image out to the chosen file
+                    byte[] jpeg = new byte[buffer.remaining()];
+                    buffer.get(jpeg);
+                    ostream.write(jpeg);
+                } catch (FileNotFoundException ex) {
+                    Log.e(TAG, "Unable to open output file for writing", ex);
+                } catch (IOException ex) {
+                    Log.e(TAG, "Failed to write the image to the output file", ex);
+                }
+            } catch (IOException ex) {
+                Log.e(TAG, "Unable to create a new output file", ex);
+            } finally {
+                mCapture.close();
+            }
+        }
+    }
+}
diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk
new file mode 100644
index 0000000..0b58243
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraTooTests
+LOCAL_INSTRUMENTATION_FOR := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
new file mode 100644
index 0000000..30210ba
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.camera2.cameratoo.tests">
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application android:label="CameraToo">
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.example.android.camera2.cameratoo"
+        android:label="CameraToo tests" />
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
new file mode 100644
index 0000000..3acca5a
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.camera2.cameratoo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.Image;
+import android.os.Environment;
+import android.util.Size;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.example.android.camera2.cameratoo.CameraTooActivity;
+import org.junit.Test;
+
+public class CameraTooTest {
+    private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) {
+        assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0);
+        assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs),
+                rel.compare(rhs, lhs), 0);
+    }
+
+    private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) {
+        assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0);
+        assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs),
+                rel.compare(rhs, lhs) > 0);
+    }
+
+    @Test
+    public void compareSizesByArea() {
+        Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+        Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+        Size largeSquare = new Size(5, 5);
+        Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea();
+
+        assertComparatorEq(empty, fatAndFlat, rel);
+        assertComparatorEq(empty, tallAndThin, rel);
+        assertComparatorEq(fatAndFlat, empty, rel);
+        assertComparatorEq(fatAndFlat, tallAndThin, rel);
+        assertComparatorEq(tallAndThin, empty, rel);
+        assertComparatorEq(tallAndThin, fatAndFlat, rel);
+
+        assertComparatorEq(smallSquare, horizRect, rel);
+        assertComparatorEq(smallSquare, vertRect, rel);
+        assertComparatorEq(horizRect, smallSquare, rel);
+        assertComparatorEq(horizRect, vertRect, rel);
+        assertComparatorEq(vertRect, smallSquare, rel);
+        assertComparatorEq(vertRect, horizRect, rel);
+
+        assertComparatorLt(empty, smallSquare, rel);
+        assertComparatorLt(empty, horizRect, rel);
+        assertComparatorLt(empty, vertRect, rel);
+
+        assertComparatorLt(fatAndFlat, smallSquare, rel);
+        assertComparatorLt(fatAndFlat, horizRect, rel);
+        assertComparatorLt(fatAndFlat, vertRect, rel);
+
+        assertComparatorLt(tallAndThin, smallSquare, rel);
+        assertComparatorLt(tallAndThin, horizRect, rel);
+        assertComparatorLt(tallAndThin, vertRect, rel);
+
+        assertComparatorLt(empty, largeSquare, rel);
+        assertComparatorLt(fatAndFlat, largeSquare, rel);
+        assertComparatorLt(tallAndThin, largeSquare, rel);
+        assertComparatorLt(smallSquare, largeSquare, rel);
+        assertComparatorLt(horizRect, largeSquare, rel);
+        assertComparatorLt(vertRect, largeSquare, rel);
+    }
+
+    private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) {
+        Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight);
+        assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict),
+                verdict, expected);
+    }
+
+    @Test
+    public void chooseBigEnoughSize() {
+        Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+        Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+        Size largeSquare = new Size(5, 5);
+        Size[] siz =
+                { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare };
+
+        assertOptimalSize(siz, 0, 0, empty);
+
+        assertOptimalSize(siz, 1, 0, fatAndFlat);
+        assertOptimalSize(siz, 0, 1, tallAndThin);
+
+        assertOptimalSize(siz, 4, 4, smallSquare);
+        assertOptimalSize(siz, 1, 1, smallSquare);
+        assertOptimalSize(siz, 2, 1, smallSquare);
+        assertOptimalSize(siz, 1, 2, smallSquare);
+        assertOptimalSize(siz, 3, 4, smallSquare);
+        assertOptimalSize(siz, 4, 3, smallSquare);
+
+        assertOptimalSize(siz, 8, 2, horizRect);
+        assertOptimalSize(siz, 5, 1, horizRect);
+        assertOptimalSize(siz, 5, 2, horizRect);
+
+        assertOptimalSize(siz, 2, 8, vertRect);
+        assertOptimalSize(siz, 1, 5, vertRect);
+        assertOptimalSize(siz, 2, 5, vertRect);
+
+        assertOptimalSize(siz, 5, 5, largeSquare);
+        assertOptimalSize(siz, 3, 5, largeSquare);
+        assertOptimalSize(siz, 5, 3, largeSquare);
+    }
+
+    private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() {
+        @Override
+        public boolean accept(File dir, String filename) {
+            return filename.indexOf("cameratoo") == 0 &&
+                    filename.indexOf(".jpg") == filename.length() - ".jpg".length();
+        }};
+
+    private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) {
+        Set<T> result = new HashSet<T>(after);
+        result.removeAll(before);
+        return result;
+    }
+
+    @Test
+    public void capturedImageSaver() throws FileNotFoundException, IOException {
+        ByteBuffer buf = ByteBuffer.allocate(25);
+        for(int index = 0; index < buf.capacity(); ++index)
+            buf.put(index, (byte) index);
+
+        Image.Plane plane = mock(Image.Plane.class);
+        when(plane.getBuffer()).thenReturn(buf);
+        when(plane.getPixelStride()).thenReturn(1);
+        when(plane.getRowStride()).thenReturn(5);
+
+        Image.Plane[] onlyPlaneThatMatters = { plane };
+        Image image = mock(Image.class);
+        when(image.getPlanes()).thenReturn(onlyPlaneThatMatters);
+        when(image.getWidth()).thenReturn(5);
+        when(image.getHeight()).thenReturn(5);
+
+        File picturesFolder =
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+        Set<File> preListing =
+                new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+
+        CameraTooActivity.CapturedImageSaver saver =
+                new CameraTooActivity.CapturedImageSaver(image);
+        saver.run();
+
+        Set<File> postListing =
+                new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+        Set<File> newFiles = newlyAddedElements(preListing, postListing);
+
+        assertEquals(newFiles.size(), 1);
+
+        File picture = newFiles.iterator().next();
+        FileInputStream istream = new FileInputStream(picture);
+
+        for(int count = 0; count < buf.capacity(); ++count) {
+            assertEquals(istream.read(), buf.get(count));
+        }
+        assertEquals(istream.read(), -1);
+        assertTrue(picture.delete());
+    }
+}
diff --git a/tests/IdleServiceTest/Android.mk b/tests/IdleServiceTest/Android.mk
deleted file mode 100644
index a7879c5..0000000
--- a/tests/IdleServiceTest/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := IdleServiceTest
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/tests/IdleServiceTest/AndroidManifest.xml b/tests/IdleServiceTest/AndroidManifest.xml
deleted file mode 100644
index 16d2324..0000000
--- a/tests/IdleServiceTest/AndroidManifest.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.idleservicetest">
-
-    <application>
-        <service android:name="TestService"
-                 android:exported="true"
-                 android:enabled="true"
-                 android:permission="android.permission.BIND_IDLE_SERVICE" >
-            <intent-filter>
-                <action android:name="android.service.idle.IdleService" />
-            </intent-filter>
-        </service>
-
-        <service android:name="CrashingTestService"
-                 android:exported="true"
-                 android:enabled="true"
-                 android:permission="android.permission.BIND_IDLE_SERVICE" >
-            <intent-filter>
-                <action android:name="android.service.idle.IdleService" />
-            </intent-filter>
-        </service>
-
-        <service android:name="TimeoutTestService"
-                 android:exported="true"
-                 android:enabled="true"
-                 android:permission="android.permission.BIND_IDLE_SERVICE" >
-            <intent-filter>
-                <action android:name="android.service.idle.IdleService" />
-            </intent-filter>
-        </service>
-
-        <!-- UnpermissionedTestService should never run because it does
-             not require the necessary permission in its <service> block -->
-        <service android:name="UnpermissionedTestService"
-                 android:exported="true"
-                 android:enabled="true" >
-            <intent-filter>
-                <action android:name="android.service.idle.IdleService" />
-            </intent-filter>
-        </service>
-
-    </application>
-</manifest>
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
deleted file mode 100644
index 022ebcf..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
+++ /dev/null
@@ -1,52 +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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.os.Handler;
-import android.util.Log;
-
-public class CrashingTestService extends IdleService {
-    static final String TAG = "CrashingTestService";
-
-    String mNull = null;
-
-    @Override
-    public boolean onIdleStart() {
-        Log.i(TAG, "Idle maintenance: onIdleStart()");
-
-        Handler h = new Handler();
-        Runnable r = new Runnable() {
-            @Override
-            public void run() {
-                Log.i(TAG, "Explicitly crashing");
-                if (mNull.equals("")) {
-                    Log.i(TAG, "won't happen");
-                }
-            }
-        };
-        Log.i(TAG, "Posting explicit crash in 15 seconds");
-        h.postDelayed(r, 15 * 1000);
-        return true;
-    }
-
-    @Override
-    public void onIdleStop() {
-        Log.i(TAG, "Idle maintenance: onIdleStop()");
-    }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
deleted file mode 100644
index 7e9805f..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.os.Handler;
-import android.util.Log;
-
-public class TestService extends IdleService {
-    static final String TAG = "TestService";
-
-    @Override
-    public boolean onIdleStart() {
-        Log.i(TAG, "Idle maintenance: onIdleStart()");
-
-        Handler h = new Handler();
-        Runnable r = new Runnable() {
-            @Override
-            public void run() {
-                Log.i(TAG, "Explicitly finishing idle");
-                finishIdle();
-            }
-        };
-        Log.i(TAG, "Posting explicit finish in 15 seconds");
-        h.postDelayed(r, 15 * 1000);
-        return true;
-    }
-
-    @Override
-    public void onIdleStop() {
-        Log.i(TAG, "Idle maintenance: onIdleStop()");
-    }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
deleted file mode 100644
index b2ba21b..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.util.Log;
-
-public class TimeoutTestService extends IdleService {
-    private static final String TAG = "TimeoutTestService";
-
-    @Override
-    public boolean onIdleStart() {
-        Log.i(TAG, "onIdleStart() but anticipating time-slice timeout");
-        return true;
-    }
-
-    @Override
-    public void onIdleStop() {
-        Log.i(TAG, "onIdleStop() so we're done");
-    }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
deleted file mode 100644
index b9fe32b..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
+++ /dev/null
@@ -1,38 +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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.util.Log;
-
-// Should never be invoked because its manifest declaration does not
-// require the necessary permission.
-public class UnpermissionedTestService extends IdleService {
-    private static final String TAG = "UnpermissionedTestService";
-
-    @Override
-    public boolean onIdleStart() {
-        Log.e(TAG, "onIdleStart() for this service should never be called!");
-        return false;
-    }
-
-    @Override
-    public void onIdleStop() {
-        Log.e(TAG, "onIdleStop() for this service should never be called!");
-    }
-
-}
diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml
index 7431737..9654197 100644
--- a/tests/JobSchedulerTestApp/AndroidManifest.xml
+++ b/tests/JobSchedulerTestApp/AndroidManifest.xml
@@ -25,6 +25,7 @@
 
         <service
             android:name=".service.TestJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE"
             android:exported="true"/>
     </application>
 
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
index 393c594..15050ef 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
@@ -17,8 +17,8 @@
 package com.android.demo.jobSchedulerApp;
 
 import android.app.Activity;
-import android.app.task.Task;
-import android.app.task.TaskParams;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -80,10 +80,10 @@
     RadioButton mWiFiConnectivityRadioButton;
     RadioButton mAnyConnectivityRadioButton;
     ComponentName mServiceComponent;
-    /** Service object to interact scheduled tasks. */
+    /** Service object to interact scheduled jobs. */
     TestJobService mTestService;
 
-    private static int kTaskId = 0;
+    private static int kJobId = 0;
 
     Handler mHandler = new Handler(/* default looper */) {
         @Override
@@ -112,7 +112,7 @@
     }
 
     /**
-     * UI onclick listener to schedule a task. What this task is is defined in
+     * UI onclick listener to schedule a job. What this job is is defined in
      * TestJobService#scheduleJob()
      */
     public void scheduleJob(View v) {
@@ -120,7 +120,7 @@
             return;
         }
 
-        Task.Builder builder = new Task.Builder(kTaskId++, mServiceComponent);
+        JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
 
         String delay = mDelayEditText.getText().toString();
         if (delay != null && !TextUtils.isEmpty(delay)) {
@@ -133,9 +133,9 @@
         boolean requiresUnmetered = mWiFiConnectivityRadioButton.isSelected();
         boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isSelected();
         if (requiresUnmetered) {
-            builder.setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED);
+            builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
         } else if (requiresAnyConnectivity) {
-            builder.setRequiredNetworkCapabilities(Task.NetworkType.ANY);
+            builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
         }
 
         mTestService.scheduleJob(builder.build());
@@ -143,24 +143,24 @@
     }
 
     /**
-     * UI onclick listener to call taskFinished() in our service.
+     * UI onclick listener to call jobFinished() in our service.
      */
     public void finishJob(View v) {
         if (!ensureTestService()) {
             return;
         }
-        mTestService.callTaskFinished();
+        mTestService.callJobFinished();
         mParamsTextView.setText("");
     }
 
-    public void onReceivedStartTask(TaskParams params) {
+    public void onReceivedStartJob(JobParameters params) {
         mShowStartView.setBackgroundColor(startJobColor);
         Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
         mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
-        mParamsTextView.setText("Executing: " + params.getTaskId() + " " + params.getExtras());
+        mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras());
     }
 
-    public void onReceivedStopTask() {
+    public void onReceivedStopJob() {
         mShowStopView.setBackgroundColor(stopJobColor);
         Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
         mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
index 7dd3cf1..bf8e887 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -16,28 +16,20 @@
 
 package com.android.demo.jobSchedulerApp.service;
 
-import android.app.Service;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.app.task.TaskParams;
-import android.app.task.TaskService;
-import android.content.ComponentName;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Binder;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.demo.jobSchedulerApp.MainActivity;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.List;
 
 
 /**
@@ -52,7 +44,7 @@
  * lifecycle of our and provide a handle to said SyncAdapter to the OS on
  * request.
  */
-public class TestJobService extends TaskService {
+public class TestJobService extends JobService {
     private static final String TAG = "SyncService";
 
     @Override
@@ -82,44 +74,44 @@
     }
 
     @Override
-    public boolean onStartTask(TaskParams params) {
-        taskParamsMap.add(params);
+    public boolean onStartJob(JobParameters params) {
+        jobParamsMap.add(params);
         if (mActivity != null) {
-            mActivity.onReceivedStartTask(params);
+            mActivity.onReceivedStartJob(params);
         }
-        Log.i(TAG, "on start task: " + params.getTaskId());
+        Log.i(TAG, "on start job: " + params.getJobId());
         return true;
     }
 
     @Override
-    public boolean onStopTask(TaskParams params) {
-        taskParamsMap.remove(params);
-        mActivity.onReceivedStopTask();
-        Log.i(TAG, "on stop task: " + params.getTaskId());
+    public boolean onStopJob(JobParameters params) {
+        jobParamsMap.remove(params);
+        mActivity.onReceivedStopJob();
+        Log.i(TAG, "on stop job: " + params.getJobId());
         return true;
     }
 
     MainActivity mActivity;
-    private final LinkedList<TaskParams> taskParamsMap = new LinkedList<TaskParams>();
+    private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
 
     public void setUiCallback(MainActivity activity) {
         mActivity = activity;
     }
 
     /** Send job to the JobScheduler. */
-    public void scheduleJob(Task t) {
+    public void scheduleJob(JobInfo t) {
         Log.d(TAG, "Scheduling job");
-        TaskManager tm =
-                (TaskManager) getSystemService(Context.TASK_SERVICE);
+        JobScheduler tm =
+                (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
         tm.schedule(t);
     }
 
-    public boolean callTaskFinished() {
-        TaskParams params = taskParamsMap.poll();
+    public boolean callJobFinished() {
+        JobParameters params = jobParamsMap.poll();
         if (params == null) {
             return false;
         } else {
-            taskFinished(params, false);
+            jobFinished(params, false);
             return true;
         }
     }
diff --git a/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java
new file mode 100644
index 0000000..45e5216
--- /dev/null
+++ b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java
@@ -0,0 +1,64 @@
+package com.android.speech.tts;
+
+import android.speech.tts.TtsEngines;
+import android.test.InstrumentationTestCase;
+
+import java.util.Locale;
+
+public class TtsEnginesTests extends InstrumentationTestCase {
+    private TtsEngines mTtsHelper;
+
+    @Override
+    public void setUp() {
+        mTtsHelper = new TtsEngines(getInstrumentation().getContext());
+    }
+
+    public void testParseLocaleString() {
+        assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-usa"));
+        assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-USA"));
+        assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en-US"));
+        assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en_us"));
+        assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng_US"));
+        assertEquals(new Locale("en", "US", "foobar"),
+                mTtsHelper.parseLocaleString("eng_US-foobar"));
+        assertEquals(new Locale("en", "", "foobar"), mTtsHelper.parseLocaleString("eng__foobar"));
+        assertNull(mTtsHelper.parseLocaleString("cc_xx_barbar"));
+        assertNull(mTtsHelper.parseLocaleString("cc--barbar"));
+
+        assertEquals(new Locale("en"), mTtsHelper.parseLocaleString("eng"));
+        assertEquals(new Locale("en","US","var"), mTtsHelper.parseLocaleString("eng-USA-var"));
+    }
+
+    public void testToOldLocaleStringFormat() {
+        assertArraysEqual(new String[]{"deu", "DEU", ""},
+                TtsEngines.toOldLocaleStringFormat(new Locale("de", "DE")));
+        assertArraysEqual(new String[]{"deu", "", ""},
+                TtsEngines.toOldLocaleStringFormat(new Locale("de")));
+        assertArraysEqual(new String[]{"eng", "", ""},
+                TtsEngines.toOldLocaleStringFormat(new Locale("en")));
+        assertArraysEqual(new String[]{"eng", "USA", ""},
+                TtsEngines.toOldLocaleStringFormat(new Locale("foo")));
+    }
+
+    public void testGetLocalePrefForEngine() {
+        assertEquals(new Locale("en", "US"),
+                mTtsHelper.getLocalePrefForEngine("foo","foo:en-US"));
+        assertEquals(new Locale("en", "US"),
+                mTtsHelper.getLocalePrefForEngine("foo","foo:eng-usa"));
+        assertEquals(new Locale("en", "US"),
+                mTtsHelper.getLocalePrefForEngine("foo","foo:eng_USA"));
+        assertEquals(new Locale("de", "DE"),
+                mTtsHelper.getLocalePrefForEngine("foo","foo:deu-deu"));
+        assertEquals(Locale.getDefault(),
+                mTtsHelper.getLocalePrefForEngine("foo","foo:,bar:xx"));
+        assertEquals(Locale.getDefault(),
+                mTtsHelper.getLocalePrefForEngine("other","foo:,bar:xx"));
+    }
+
+    private void assertArraysEqual(String[] expected, String[] actual) {
+        assertEquals("array length", expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("index " + i, expected[i], actual[i]);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 113dce3..db2efc3 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -17,13 +17,13 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.dynamic" >
+
     <uses-sdk android:minSdkVersion="20" />
 
     <application
         android:hardwareAccelerated="true"
         android:label="vector" >
-
-         <activity
+        <activity
             android:name="VectorDrawablePerformance"
             android:label="Vector Performance" >
             <intent-filter>
@@ -31,13 +31,13 @@
 
                 <category android:name="com.android.test.dynamic.TEST" />
             </intent-filter>
-
         </activity>
         <activity
             android:name="VectorDrawableAnimation"
             android:label="VectorTestAnimation" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+
                 <category android:name="com.android.test.dynamic.TEST" />
             </intent-filter>
         </activity>
@@ -52,6 +52,15 @@
             </intent-filter>
         </activity>
         <activity
+            android:name="AnimatedVectorDrawableTest"
+            android:label="AnimatedVectorDrawableTest" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="com.android.test.dynamic.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
             android:name="VectorDrawable01"
             android:label="VectorTest1" >
             <intent-filter>
@@ -68,7 +77,6 @@
 
                 <category android:name="com.android.test.dynamic.TEST" />
             </intent-filter>
-
         </activity>
         <activity
             android:name="VectorDrawableStaticPerf"
@@ -78,9 +86,7 @@
 
                 <category android:name="com.android.test.dynamic.TEST" />
             </intent-filter>
-
         </activity>
-
         <activity
             android:name="VectorCheckbox"
             android:label="On a Checkbox" >
@@ -89,7 +95,6 @@
 
                 <category android:name="com.android.test.dynamic.TEST" />
             </intent-filter>
-
         </activity>
         <activity
             android:name="VectorPathChecking"
@@ -99,7 +104,6 @@
 
                 <category android:name="com.android.test.dynamic.TEST" />
             </intent-filter>
-
         </activity>
     </application>
 
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml
new file mode 100644
index 0000000..d47e019
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation01.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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <set android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="5000"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="0"
+            android:valueTo="1"
+            android:valueType="floatType" />
+        <objectAnimator
+            android:duration="5000"
+            android:propertyName="trimPathEnd"
+            android:valueFrom="1"
+            android:valueTo="0"
+            android:valueType="floatType" />
+    </set>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
new file mode 100644
index 0000000..3bf2865
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="5000"
+        android:propertyName="fill"
+        android:valueFrom="#FF000000"
+        android:valueTo="#FFFF0000"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
new file mode 100644
index 0000000..72beba2
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="6000"
+        android:propertyName="rotation"
+        android:valueFrom="0"
+        android:valueTo="360"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
new file mode 100644
index 0000000..ff86668
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="9000"
+        android:propertyName="rotation"
+        android:valueFrom="0"
+        android:valueTo="360"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
new file mode 100644
index 0000000..b8681b6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -0,0 +1,36 @@
+<!--
+ 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-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/vector_drawable12" >
+
+    <target
+        android:name="pie1"
+        android:animation="@anim/trim_path_animation01" />
+    <target
+        android:name="v"
+        android:animation="@anim/trim_path_animation02" />
+
+    <target
+        android:name="rotationGroup"
+        android:animation="@anim/trim_path_animation03" />
+    <target
+        android:name="rotationGroup3"
+        android:animation="@anim/trim_path_animation03" />
+    <target
+        android:name="rotationGroupBlue"
+        android:animation="@anim/trim_path_animation03" />
+
+</animated-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 3042f6a..e28ec41 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -23,11 +23,15 @@
         android:viewportHeight="600"
         android:viewportWidth="600" />
 
-    <group>
+    <group
+        android:name="rotationGroup"
+        android:pivotX="300.0"
+        android:pivotY="300.0"
+        android:rotation="45.0" >
         <path
             android:name="pie1"
-            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
             android:fill="#00000000"
+            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
             android:stroke="#FF00FF00"
             android:strokeWidth="70"
             android:trimPathEnd=".75"
@@ -36,7 +40,66 @@
         <path
             android:name="v"
             android:fill="#FF00FF00"
-            android:pathData="M300,70 l 0,-70 70,70 -70,70z"/>
+            android:pathData="M300,70 l 0,-70 70,70 -70,70z" />
+
+        <group
+            android:name="translateToCenterGroup"
+            android:rotation="0.0"
+            android:translateX="200.0"
+            android:translateY="200.0" >
+            <path
+                android:name="twoLines"
+                android:pathData="@string/twoLinePathData"
+                android:stroke="#FFFF0000"
+                android:strokeWidth="20" />
+
+            <group
+                android:name="rotationGroup2"
+                android:pivotX="0.0"
+                android:pivotY="0.0"
+                android:rotation="-45.0" >
+                <path
+                    android:name="twoLines1"
+                    android:pathData="@string/twoLinePathData"
+                    android:stroke="#FF00FF00"
+                    android:strokeWidth="20" />
+
+                <group
+                    android:name="translateGroupHalf"
+                    android:translateX="65.0"
+                    android:translateY="80.0" >
+                    <group
+                        android:name="rotationGroup3"
+                        android:pivotX="-65.0"
+                        android:pivotY="-80.0"
+                        android:rotation="-45.0" >
+                        <path
+                            android:name="twoLines2"
+                            android:fill="#FF00FF00"
+                            android:pathData="@string/twoLinePathData"
+                            android:stroke="#FF00FF00"
+                            android:strokeWidth="20" />
+
+                        <group
+                            android:name="translateGroup"
+                            android:translateX="65.0"
+                            android:translateY="80.0" >
+                            <group
+                                android:name="rotationGroupBlue"
+                                android:pivotX="-65.0"
+                                android:pivotY="-80.0"
+                                android:rotation="-45.0" >
+                                <path
+                                    android:name="twoLines3"
+                                    android:pathData="@string/twoLinePathData"
+                                    android:stroke="#FF0000FF"
+                                    android:strokeWidth="20" />
+                            </group>
+                        </group>
+                    </group>
+                </group>
+            </group>
+        </group>
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
new file mode 100644
index 0000000..6e864fa
--- /dev/null
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.dynamic;
+
+import android.app.Activity;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+public class AnimatedVectorDrawableTest extends Activity {
+    private static final String LOGCAT = "VectorDrawableAnimationTest";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Button button = new Button(this);
+        button.setBackgroundResource(R.drawable.animation_vector_drawable01);
+        button.setOnClickListener(new View.OnClickListener() {
+                @Override
+            public void onClick(View v) {
+                AnimatedVectorDrawable frameAnimation = (AnimatedVectorDrawable) v.getBackground();
+                frameAnimation.start();
+            }
+        });
+
+        setContentView(button);
+    }
+}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
index 99de037..93b06b6 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
@@ -14,6 +14,7 @@
 
 package com.android.test.dynamic;
 
+import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.graphics.drawable.AnimationDrawable;
 import android.os.Bundle;
@@ -27,7 +28,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        Button button = new Button(this);
+        final Button button = new Button(this);
         button.setBackgroundResource(R.drawable.animation_drawable_vector);
 
         button.setOnClickListener(new View.OnClickListener() {
diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk
new file mode 100644
index 0000000..2ab3d02
--- /dev/null
+++ b/tests/VoiceEnrollment/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := VoiceEnrollment
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml
new file mode 100644
index 0000000..6321222
--- /dev/null
+++ b/tests/VoiceEnrollment/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.test.voiceenrollment">
+
+    <application
+        android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
+        <activity android:name="TestEnrollmentActivity" android:label="Voice Enrollment Application"
+                  android:theme="@android:style/Theme.Material.Light.Voice">
+            <intent-filter>
+                <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <meta-data android:name="android.voice_enrollment"
+            android:resource="@xml/enrollment_application"/>
+    </application>
+</manifest>
diff --git a/core/java/android/app/task/TaskParams.aidl b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
similarity index 61%
copy from core/java/android/app/task/TaskParams.aidl
copy to tests/VoiceEnrollment/res/xml/enrollment_application.xml
index 9b25855..710a0ac 100644
--- a/core/java/android/app/task/TaskParams.aidl
+++ b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
 /**
- * Copyright 2014, 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.
@@ -13,7 +15,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+-->
 
-package android.app.task;
-
-parcelable TaskParams;
\ No newline at end of file
+<voice-enrollment-application xmlns:android="http://schemas.android.com/apk/res/android"
+    android:searchKeyphraseId="101"
+    android:searchKeyphrase="Hello There"
+    android:searchKeyphraseSupportedLocales="en-US,en-GB,fr-FR,de-DE" />
diff --git a/core/java/android/app/task/Task.aidl b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
similarity index 76%
copy from core/java/android/app/task/Task.aidl
copy to tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
index 1f25439..7fbd965 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package android.app.task;
+package com.android.test.voiceenrollment;
 
-parcelable Task;
- 
\ No newline at end of file
+import android.app.Activity;
+
+public class TestEnrollmentActivity extends Activity {
+    // TODO(sansid): Add a test enrollment flow here.
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index d40b05f..00c2c64 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -21,6 +21,8 @@
 import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 
+import java.util.Arrays;
+
 public class MainInteractionService extends VoiceInteractionService {
     static final String TAG = "MainInteractionService";
 
@@ -28,6 +30,9 @@
     public void onCreate() {
         super.onCreate();
         Log.i(TAG, "Creating " + this);
+        Log.i(TAG, "Keyphrase enrollment error? " + getKeyphraseEnrollmentInfo().getParseError());
+        Log.i(TAG, "Keyphrase enrollment meta-data: "
+                + Arrays.toString(getKeyphraseEnrollmentInfo().getKeyphrases()));
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index af22f44..36102f1 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -151,7 +151,7 @@
     @Override
     public View inflate(int resource, ViewGroup root) {
         Context context = getContext();
-        if (context instanceof ContextThemeWrapper) {
+        while (context instanceof ContextThemeWrapper) {
             context = ((ContextThemeWrapper) context).getBaseContext();
         }
         if (context instanceof BridgeContext) {
@@ -217,7 +217,7 @@
 
     private void setupViewInContext(View view, AttributeSet attrs) {
         Context context = getContext();
-        if (context instanceof ContextThemeWrapper) {
+        while (context instanceof ContextThemeWrapper) {
             context = ((ContextThemeWrapper) context).getBaseContext();
         }
         if (context instanceof BridgeContext) {
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
index 0dddf3d..dafc96b 100644
--- a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -48,7 +48,7 @@
             AttributeSet attrs) {
         if (menuItem instanceof BridgeMenuItemImpl) {
             Context context = thisInflater.getContext();
-            if (context instanceof ContextThemeWrapper) {
+            while (context instanceof ContextThemeWrapper) {
                 context = ((ContextThemeWrapper) context).getBaseContext();
             }
             if (context instanceof BridgeContext) {
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
index cdb839a..8d1d0c1 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -42,7 +42,7 @@
             CharSequence title, int showAsAction) {
         super(menu, group, id, categoryOrder, ordering, title, showAsAction);
         Context context = menu.getContext();
-        if (context instanceof ContextThemeWrapper) {
+        while (context instanceof ContextThemeWrapper) {
             context = ((ContextThemeWrapper) context).getBaseContext();
         }
         if (context instanceof BridgeContext) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 09e6878..e1064b1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -197,7 +197,7 @@
     }
 
     @Override
-    public void onRectangleOnScreenRequested(IBinder window, Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequested(IBinder window, Rect rectangle) {
         // pass for now.
     }
 
diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt
index 6e0a300..32625ae 100644
--- a/tools/layoutlib/create/README.txt
+++ b/tools/layoutlib/create/README.txt
@@ -119,8 +119,8 @@
 
 The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but updates the
 references in all classes. This is used to update the references of classes in the java package that
-were added in the Dalvik VM but are not a part of the standard JVM. The existing classes are
-modified to update all references to these non-standard classes. An alternate implementation of
+were added in the Dalvik VM but are not a part of the Desktop VM. The existing classes are
+modified to update all references to these non-desktop classes. An alternate implementation of
 these (com.android.tools.layoutlib.java.*) is injected.
 
 RenameClassAdapter and RefactorClassAdapter both inherit from AbstractClassAdapter which changes the
@@ -130,11 +130,15 @@
 valid StackMapTable. As a side benefit of this, we can continue to support Java 6 because Java 7 on
 Mac has horrible font rendering support.
 
+ReplaceMethodCallsAdapter replaces calls to certain methods. Currently, it only rewrites calls to
+java.lang.System.arraycopy([CI[CII)V, which is not part of the Desktop VM to call the more general
+method java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V.
+
 The ClassAdapters are chained together to achieve the desired output. (Look at section 2.2.7
 Transformation chains in the asm user guide, link in the References.) The order of execution of
 these is:
 ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
-RefactorClassAdapter -> ClassWriter
+RefactorClassAdapter -> [ReplaceMethodCallsAdapter] -> ClassWriter
 
 - Method stubs
 --------------
@@ -169,7 +173,7 @@
 - AutoCloseable and Objects are part of Java 7. To enable us to still run on Java 6, new classes are
   injected. The implementation for these classes has been taken from Android's libcore
   (platform/libcore/luni/src/main/java/java/...).
-- Charsets, IntegralToString and UnsafeByteSequence are not part of the standard JAVA VM. They are
+- Charsets, IntegralToString and UnsafeByteSequence are not part of the Desktop VM. They are
   added to the Dalvik VM for performance reasons. An implementation that is very close to the
   original (which is at platform/libcore/luni/src/main/java/...) is injected. Since these classees
   were in part of the java package, where we can't inject classes, all references to these have been
@@ -209,7 +213,7 @@
 
 This is very similar to the Renaming classes except that it also updates the reference in all
 classes. This is done for classes which are added to the Dalvik VM for performance reasons but are
-not present in the Standard Java VM. An implementation for these classes is also injected.
+not present in the Desktop VM. An implementation for these classes is also injected.
 
 
 5- Method erasure based on return type
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 3e75c9e..8373e30 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -32,6 +32,7 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -63,7 +64,8 @@
     private final Set<String> mExcludedClasses;
     /** Glob patterns of files to keep as is. */
     private final String[] mIncludeFileGlobs;
-    /** Copy these files into the output as is. */
+    /** Internal names of classes that contain method calls that need to be rewritten. */
+    private final Set<String> mReplaceMethodCallClasses = new HashSet<String>();
 
     /**
      * Creates a new analyzer.
@@ -109,6 +111,7 @@
             mGen.setKeep(found);
             mGen.setDeps(deps);
             mGen.setCopyFiles(filesFound);
+            mGen.setRewriteMethodCallClasses(mReplaceMethodCallClasses);
         }
     }
 
@@ -118,7 +121,7 @@
      *
      * @param classes The map of class name => ASM ClassReader. Class names are
      *                in the form "android.view.View".
-     * @param fileFound The map of file name => InputStream. The file name is
+     * @param filesFound The map of file name => InputStream. The file name is
      *                  in the form "android/data/dataFile".
      */
     void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
@@ -143,8 +146,8 @@
                     String className = classReaderToClassName(cr);
                     classes.put(className, cr);
                 } else {
-                    for (int i = 0; i < includeFilePatterns.length; ++i) {
-                        if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
+                    for (Pattern includeFilePattern : includeFilePatterns) {
+                        if (includeFilePattern.matcher(entry.getName()).matches()) {
                             filesFound.put(entry.getName(), zip.getInputStream(entry));
                             break;
                         }
@@ -321,6 +324,7 @@
                 deps, new_deps);
 
         for (ClassReader cr : inOutKeepClasses.values()) {
+            visitor.setClassName(cr.getClassName());
             cr.accept(visitor, 0 /* flags */);
         }
 
@@ -367,6 +371,8 @@
         /** New classes to keep as-is found by this visitor. */
         private final Map<String, ClassReader> mOutKeep;
 
+        private String mClassName;
+
         /**
          * Creates a new visitor that will find all the dependencies for the visited class.
          * Types which are already in the zipClasses, keepClasses or inDeps are not marked.
@@ -390,6 +396,10 @@
             mOutDeps = outDeps;
         }
 
+        private void setClassName(String className) {
+            mClassName = className;
+        }
+
         /**
          * Considers the given class name as a dependency.
          * If it does, add to the mOutDeps map.
@@ -429,7 +439,7 @@
             // - android classes are added to dependencies
             // - non-android classes are added to the list of classes to keep as-is (they don't need
             //   to be stubbed).
-            if (className.indexOf("android") >= 0) {  // TODO make configurable
+            if (className.contains("android")) {  // TODO make configurable
                 mOutDeps.put(className, cr);
             } else {
                 mOutKeep.put(className, cr);
@@ -594,7 +604,7 @@
             // type and exceptions do not use generic types.
             considerSignature(signature);
 
-            return new MyMethodVisitor();
+            return new MyMethodVisitor(mClassName);
         }
 
         @Override
@@ -614,8 +624,11 @@
 
         private class MyMethodVisitor extends MethodVisitor {
 
-            public MyMethodVisitor() {
+            private String mOwnerClass;
+
+            public MyMethodVisitor(String ownerClass) {
                 super(Opcodes.ASM4);
+                mOwnerClass = ownerClass;
             }
 
 
@@ -709,6 +722,13 @@
                 considerName(owner);
                 // desc is the method's descriptor (see Type).
                 considerDesc(desc);
+
+
+                // Check if method is java.lang.System.arrayCopy([CI[CII)V
+                if (owner.equals("java/lang/System") && name.equals("arraycopy")
+                        && desc.equals("([CI[CII)V")) {
+                    mReplaceMethodCallClasses.add(mOwnerClass);
+                }
             }
 
             // instruction multianewarray, whatever that is
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 207d8ae..c96a143 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -21,7 +21,6 @@
 import org.objectweb.asm.ClassWriter;
 
 import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -55,6 +54,8 @@
     private Map<String, ClassReader> mDeps;
     /** All files that are to be copied as-is. */
     private Map<String, InputStream> mCopyFiles;
+    /** All classes where certain method calls need to be rewritten. */
+    private Set<String> mReplaceMethodCallsClasses;
     /** Counter of number of classes renamed during transform. */
     private int mRenameCount;
     /** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
@@ -133,7 +134,7 @@
             assert i + 1 < n;
             String oldFqcn = binaryToInternalClassName(refactorClasses[i]);
             String newFqcn = binaryToInternalClassName(refactorClasses[i + 1]);
-            mRefactorClasses.put(oldFqcn, newFqcn);;
+            mRefactorClasses.put(oldFqcn, newFqcn);
         }
 
         // create the map of renamed class -> return type of method to delete.
@@ -203,23 +204,12 @@
         mCopyFiles = copyFiles;
     }
 
-    /** Gets the map of classes to output as-is, except if they have native methods */
-    public Map<String, ClassReader> getKeep() {
-        return mKeep;
-    }
-
-    /** Gets the map of dependencies that must be completely stubbed */
-    public Map<String, ClassReader> getDeps() {
-        return mDeps;
-    }
-
-    /** Gets the map of files to output as-is. */
-    public Map<String, InputStream> getCopyFiles() {
-        return mCopyFiles;
+    public void setRewriteMethodCallClasses(Set<String> rewriteMethodCallClasses) {
+        mReplaceMethodCallsClasses = rewriteMethodCallClasses;
     }
 
     /** Generates the final JAR */
-    public void generate() throws FileNotFoundException, IOException {
+    public void generate() throws IOException {
         TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
 
         for (Class<?> clazz : mInjectClasses) {
@@ -329,14 +319,14 @@
 
         String newName = transformName(className);
         // transformName returns its input argument if there's no need to rename the class
-        if (newName != className) {
+        if (!newName.equals(className)) {
             mRenameCount++;
             // This class is being renamed, so remove it from the list of classes not renamed.
             mClassesNotRenamed.remove(className);
         }
 
         mLog.debug("Transform %s%s%s%s", className,
-                newName == className ? "" : " (renamed to " + newName + ")",
+                newName.equals(className) ? "" : " (renamed to " + newName + ")",
                 hasNativeMethods ? " -- has natives" : "",
                 stubNativesOnly ? " -- stub natives only" : "");
 
@@ -344,8 +334,14 @@
         // original class reader.
         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
 
-        ClassVisitor cv = new RefactorClassAdapter(cw, mRefactorClasses);
-        if (newName != className) {
+        ClassVisitor cv = cw;
+
+        if (mReplaceMethodCallsClasses.contains(className)) {
+            cv = new ReplaceMethodCallsAdapter(cv);
+        }
+
+        cv = new RefactorClassAdapter(cv, mRefactorClasses);
+        if (!newName.equals(className)) {
             cv = new RenameClassAdapter(cv, className, newName);
         }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 2e952fc..ad10656 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -193,8 +193,7 @@
     private static boolean processArgs(Log log, String[] args,
             ArrayList<String> osJarPath, String[] osDestJar) {
         boolean needs_dest = true;
-        for (int i = 0; i < args.length; i++) {
-            String s = args[i];
+        for (String s : args) {
             if (s.equals("-v")) {
                 log.setVerbose(true);
             } else if (s.equals("-p")) {
@@ -212,7 +211,7 @@
                     osJarPath.add(s);
                 }
             } else {
-                log.error("Unknow argument: %s", s);
+                log.error("Unknown argument: %s", s);
                 return false;
             }
         }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
new file mode 100644
index 0000000..e57eba1
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Replaces calls to certain methods that do not exist in the Desktop VM.
+ */
+public class ReplaceMethodCallsAdapter extends ClassVisitor {
+    public ReplaceMethodCallsAdapter(ClassVisitor cv) {
+        super(Opcodes.ASM4, cv);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+        return new MyMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions));
+    }
+
+    private class MyMethodVisitor extends MethodVisitor {
+
+        public MyMethodVisitor(MethodVisitor mv) {
+            super(Opcodes.ASM4, mv);
+        }
+
+        @Override
+        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+            // Check if method is java.lang.System.arrayCopy([CI[CII)V
+            if (owner.equals("java/lang/System") && name.equals("arraycopy")
+                    && desc.equals("([CI[CII)V")) {
+                desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
+            }
+            super.visitMethodInsn(opcode, owner, name, desc);
+        }
+    }
+}
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
index aea3241..bd9b14c 100755
--- a/tools/layoutlib/rename_font/build_font.py
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -27,7 +27,7 @@
 from fontTools import ttx
 import re
 import os
-from lxml import etree
+import xml.etree.ElementTree as etree
 import shutil
 import glob
 from multiprocessing import Pool
@@ -84,14 +84,13 @@
     ttx.main(ttx_args)
     # now parse the xml file to change its PS name.
     tree = etree.parse(ttx_path)
-    encoding = tree.docinfo.encoding
     root = tree.getroot()
     for name in root.iter('name'):
       [old_ps_name, version] = get_font_info(name)
       if old_ps_name is not None and version is not None:
         new_ps_name = old_ps_name + version
         update_name(name, new_ps_name)
-    tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+    tree.write(ttx_path, xml_declaration=True, encoding='utf-8' )
     # generate the udpated font now.
     ttx_args = ['-q', '-d', dest_dir, ttx_path]
     ttx.main(ttx_args)
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
index d4c86cb..b0b69d8 100755
--- a/tools/layoutlib/rename_font/test.py
+++ b/tools/layoutlib/rename_font/test.py
@@ -14,7 +14,7 @@
 
 from fontTools import ttx
 import os
-from lxml import etree
+import xml.etree.ElementTree as etree
 import shutil
 import tempfile
 
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 99151c3..8191edd 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -89,6 +89,21 @@
      * {@hide}
      */
     public final static int UNSPECIFIED = -1;
+    /**
+     * @hide
+     * TODO: makes real freq boundaries
+     */
+    public boolean is24GHz() {
+        return frequency > 2400 && frequency < 2500;
+    }
+
+    /**
+     * @hide
+     * TODO: makes real freq boundaries
+     */
+    public boolean is5GHz() {
+        return frequency > 4900 && frequency < 5900;
+    }
 
     /** information element from beacon
      * @hide
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 192cba6..b64ad60 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -342,6 +342,12 @@
 
     /**
      * @hide
+     * Uid of app owning the BSSID
+     */
+    public int bssidOwnerUid;
+
+    /**
+     * @hide
      * BSSID list on which this configuration was seen.
      * TODO: prevent this list to grow infinitely, age-out the results
      */
@@ -405,6 +411,10 @@
     /** @hide **/
     public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70;
 
+    /** @hide
+     * 5GHz band is prefered over 2.4 if the 5GHz RSSI is higher than this threshold **/
+    public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65;
+
     /**
      * @hide
      * A summary of the RSSI and Band status for that configuration
@@ -481,11 +491,11 @@
             if (result.seen == 0)
                 continue;
 
-            if ((result.frequency > 4900) && (result.frequency < 5900)) {
+            if (result.is5GHz()) {
                 //strictly speaking: [4915, 5825]
                 //number of known BSSID on 5GHz band
                 status.num5 = status.num5 + 1;
-            } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+            } else if (result.is24GHz()) {
                 //strictly speaking: [2412, 2482]
                 //number of known BSSID on 2.4Ghz band
                 status.num24 = status.num24 + 1;
@@ -493,12 +503,12 @@
 
             if ((now_ms - result.seen) > age) continue;
 
-            if ((result.frequency > 4900) && (result.frequency < 5900)) {
+            if (result.is5GHz()) {
                 if (result.level > status.rssi5) {
                     status.rssi5 = result.level;
                     status.age5 = result.seen;
                 }
-            } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+            } else if (result.is24GHz()) {
                 if (result.level > status.rssi24) {
                     status.rssi24 = result.level;
                     status.age24 = result.seen;
@@ -547,6 +557,17 @@
      */
     public long blackListTimestamp;
 
+    /**
+     * @hide
+     * last time the system was connected to this configuration.
+     */
+    public long lastConnected;
+
+    /**
+     * @hide
+     * last time the system was disconnected to this configuration.
+     */
+    public long lastDisconnected;
 
     /**
      * Set if the configuration was self added by the framework
@@ -658,7 +679,20 @@
 
         // TODO: Add more checks
         return true;
+    }
 
+    /**
+     * Helper function, identify if a configuration is linked
+     * @hide
+     */
+    public boolean isLinked(WifiConfiguration config) {
+        if (config.linkedConfigurations != null && linkedConfigurations != null) {
+            if (config.linkedConfigurations.get(configKey()) != null
+                    && linkedConfigurations.get(config.configKey()) != null) {
+                return true;
+            }
+        }
+        return  false;
     }
 
     /**
@@ -688,6 +722,7 @@
 
     /** @hide **/
     public void setAutoJoinStatus(int status) {
+        if (status < 0) status = 0;
         if (status == 0) {
             blackListTimestamp = 0;
         }  else if (status > autoJoinStatus) {
@@ -1076,9 +1111,12 @@
             didSelfAdd = source.didSelfAdd;
             lastConnectUid = source.lastConnectUid;
             lastUpdateUid = source.lastUpdateUid;
+            bssidOwnerUid = source.bssidOwnerUid;
             creatorUid = source.creatorUid;
             peerWifiConfiguration = source.peerWifiConfiguration;
             blackListTimestamp = source.blackListTimestamp;
+            lastConnected = source.lastConnected;
+            lastDisconnected = source.lastDisconnected;
         }
     }
 
@@ -1122,6 +1160,7 @@
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
         dest.writeInt(lastUpdateUid);
+        dest.writeInt(bssidOwnerUid);
         dest.writeLong(blackListTimestamp);
     }
 
@@ -1161,6 +1200,7 @@
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
                 config.lastUpdateUid = in.readInt();
+                config.bssidOwnerUid = in.readInt();
                 config.blackListTimestamp = in.readLong();
                 return config;
             }
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index f6a94d0..54a7df2 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -62,6 +62,17 @@
     private String mBSSID;
     private WifiSsid mWifiSsid;
     private int mNetworkId;
+
+    /** @hide **/
+    public static final int INVALID_RSSI = -127;
+
+    /** @hide **/
+    public static final int MIN_RSSI = -126;
+
+    /** @hide **/
+    public static final int MAX_RSSI = 200;
+
+
     /**
      * Received Signal Strength Indicator
      */
@@ -126,12 +137,13 @@
     public int lowRssiCount;
 
     /**
-     * @hide *
+     * @hide
      */
     public int score;
 
     /**
-     * @hide *
+     * TODO: get actual timestamp and calculate true rates
+     * @hide
      */
     public void updatePacketRates(WifiLinkLayerStats stats) {
         if (stats != null) {
@@ -156,17 +168,42 @@
             rxSuccess = rxgood;
             txRetries = txretries;
         } else {
-            txBadRate = 0;
+            txBad = 0;
             txSuccess = 0;
             rxSuccess = 0;
             txRetries = 0;
+            txBadRate = 0;
+            txSuccessRate = 0;
+            rxSuccessRate = 0;
+            txRetriesRate = 0;
         }
     }
 
+
     /**
-     * Flag indicating that AP has hinted that upstream connection is metered,
-     * and sensitive to heavy data transfers.
+     * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
+     * at the Wifi HAL
+     * @hide
      */
+    public void updatePacketRates(long txPackets, long rxPackets) {
+        //paranoia
+        txBad = 0;
+        txRetries = 0;
+        txBadRate = 0;
+        txRetriesRate = 0;
+
+        txSuccessRate = (txSuccessRate * 0.5)
+                + ((double) (txPackets - txSuccess) * 0.5);
+        rxSuccessRate = (rxSuccessRate * 0.5)
+                + ((double) (rxPackets - rxSuccess) * 0.5);
+        txSuccess = txPackets;
+        rxSuccess = rxPackets;
+    }
+
+        /**
+         * Flag indicating that AP has hinted that upstream connection is metered,
+         * and sensitive to heavy data transfers.
+         */
     private boolean mMeteredHint;
 
     /** @hide */
@@ -175,11 +212,34 @@
         mBSSID = null;
         mNetworkId = -1;
         mSupplicantState = SupplicantState.UNINITIALIZED;
-        mRssi = -9999;
+        mRssi = INVALID_RSSI;
         mLinkSpeed = -1;
         mFrequency = -1;
     }
 
+    /** @hide */
+    public void reset() {
+        setInetAddress(null);
+        setBSSID(null);
+        setSSID(null);
+        setNetworkId(-1);
+        setRssi(INVALID_RSSI);
+        setLinkSpeed(-1);
+        setFrequency(-1);
+        setMeteredHint(false);
+        txBad = 0;
+        txSuccess = 0;
+        rxSuccess = 0;
+        txRetries = 0;
+        txBadRate = 0;
+        txSuccessRate = 0;
+        rxSuccessRate = 0;
+        txRetriesRate = 0;
+        lowRssiCount = 0;
+        badRssiCount = 0;
+        score = 0;
+    }
+
     /**
      * Copy constructor
      * @hide
@@ -256,7 +316,7 @@
     /**
      * Returns the received signal strength indicator of the current 802.11
      * network, in dBm.
-     * @return the RSSI, in the range -110 to 10
+     * @return the RSSI, in the range -127 to 200
      */
     public int getRssi() {
         return mRssi;
@@ -264,6 +324,10 @@
 
     /** @hide */
     public void setRssi(int rssi) {
+        if (rssi < INVALID_RSSI)
+            rssi = INVALID_RSSI;
+        if (rssi > MAX_RSSI)
+            rssi = MAX_RSSI;
         mRssi = rssi;
     }
 
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 3b65ca8..21b700d 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -153,12 +153,17 @@
             dest.writeInt(band);
             dest.writeInt(periodInMs);
             dest.writeInt(reportEvents);
-            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);
+            if (channels != null) {
+                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);
+                }
+            } else {
+                dest.writeInt(0);
             }
         }
 
@@ -211,10 +216,14 @@
 
         /** 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);
+            if (mResults != null) {
+                dest.writeInt(mResults.length);
+                for (int i = 0; i < mResults.length; i++) {
+                    ScanResult result = mResults[i];
+                    result.writeToParcel(dest, flags);
+                }
+            } else {
+                dest.writeInt(0);
             }
         }
 
@@ -324,13 +333,17 @@
             dest.writeInt(unchangedSampleSize);
             dest.writeInt(minApsBreachingThreshold);
             dest.writeInt(periodInMs);
-            dest.writeInt(hotspotInfos.length);
-            for (int i = 0; i < hotspotInfos.length; i++) {
-                HotspotInfo info = hotspotInfos[i];
-                dest.writeString(info.bssid);
-                dest.writeInt(info.low);
-                dest.writeInt(info.high);
-                dest.writeInt(info.frequencyHint);
+            if (hotspotInfos != null) {
+                dest.writeInt(hotspotInfos.length);
+                for (int i = 0; i < hotspotInfos.length; i++) {
+                    HotspotInfo info = hotspotInfos[i];
+                    dest.writeString(info.bssid);
+                    dest.writeInt(info.low);
+                    dest.writeInt(info.high);
+                    dest.writeInt(info.frequencyHint);
+                }
+            } else {
+                dest.writeInt(0);
             }
         }
 
@@ -456,13 +469,18 @@
         /** 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);
-                dest.writeInt(info.frequencyHint);
+
+            if (hotspotInfos != null) {
+                dest.writeInt(hotspotInfos.length);
+                for (int i = 0; i < hotspotInfos.length; i++) {
+                    HotspotInfo info = hotspotInfos[i];
+                    dest.writeString(info.bssid);
+                    dest.writeInt(info.low);
+                    dest.writeInt(info.high);
+                    dest.writeInt(info.frequencyHint);
+                }
+            } else {
+                dest.writeInt(0);
             }
         }
 
@@ -680,6 +698,42 @@
         }
     }
 
+    /** @hide */
+    public static class OperationResult implements Parcelable {
+        public int reason;
+        public String description;
+
+        public OperationResult(int reason, String description) {
+            this.reason = reason;
+            this.description = description;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(reason);
+            dest.writeString(description);
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<OperationResult> CREATOR =
+                new Creator<OperationResult>() {
+                    public OperationResult createFromParcel(Parcel in) {
+                        int reason = in.readInt();
+                        String description = in.readString();
+                        return new OperationResult(reason, description);
+                    }
+
+                    public OperationResult[] newArray(int size) {
+                        return new OperationResult[size];
+                    }
+                };
+    }
+
     private static class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
@@ -717,9 +771,11 @@
                 case CMD_OP_SUCCEEDED :
                     ((ActionListener) listener).onSuccess();
                     break;
-                case CMD_OP_FAILED :
-                    ((ActionListener) listener).onFailure(msg.arg1, (String)msg.obj);
-                    removeListener(msg.arg2);
+                case CMD_OP_FAILED : {
+                        OperationResult result = (OperationResult)msg.obj;
+                        ((ActionListener) listener).onFailure(result.reason, result.description);
+                        removeListener(msg.arg2);
+                    }
                     break;
                 case CMD_SCAN_RESULT :
                     ((ScanListener) listener).onResults(
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
index 8375d09..61c2b8a 100644
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -16,6 +16,8 @@
 
 package android.net.wifi.passpoint;
 
+import android.net.wifi.ScanResult;
+import android.net.wifi.passpoint.WifiPasspointPolicy;
 import android.os.Messenger;
 
 /**
@@ -27,5 +29,6 @@
 {
     Messenger getMessenger();
     int getPasspointState();
+    List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
 }
 
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 54ac71e..33ccad5 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -493,7 +493,8 @@
                 }
                 if (this.mType.equals("TLS")) {
                     result = this.mRealm.equals(other.mRealm) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
+                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
+                            this.mClientCert.equals(other.mClientCert);
                 }
                 if (this.mType.equals("SIM")) {
                     result = this.mMcc.equals(other.mMcc) &&
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
index 8ab5c1e..33db3f5 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
@@ -213,22 +213,22 @@
     public String venueName;
 
     /** list of network authentication types */
-    public List<NetworkAuthType> networkAuthType;
+    public List<NetworkAuthType> networkAuthTypeList;
 
     /** list of roaming consortium OIs */
-    public List<String> roamingConsortium;
+    public List<String> roamingConsortiumList;
 
     /** IP address availability */
     public IpAddressType ipAddrTypeAvailability;
 
-    /** NAI realm */
-    public List<NaiRealm> naiRealm;
+    /** list of NAI realm */
+    public List<NaiRealm> naiRealmList;
 
-    /** 3GPP cellular network */
-    public List<CellularNetwork> cellularNetwork;
+    /** list of 3GPP cellular network */
+    public List<CellularNetwork> cellularNetworkList;
 
-    /** fully qualified domain name (FQDN) */
-    public List<String> domainName;
+    /** list of fully qualified domain name (FQDN) */
+    public List<String> domainNameList;
 
     /** HS 2.0 operator friendly name */
     public String operatorFriendlyName;
@@ -236,10 +236,10 @@
     /** HS 2.0 wan metrics */
     public WanMetrics wanMetrics;
 
-    /** HS 2.0 list of IP proto port */
-    public List<IpProtoPort> connectionCapability;
+    /** list of HS 2.0 IP proto port */
+    public List<IpProtoPort> connectionCapabilityList;
 
-    /** HS 2.0 list of OSU providers */
+    /** list of HS 2.0 OSU providers */
     public List<WifiPasspointOsuProvider> osuProviderList;
 
     /**
@@ -286,20 +286,21 @@
     public String toString() {
         StringBuffer sb = new StringBuffer();
 
-        sb.append("BSSID: ").append(bssid);
+        sb.append("BSSID: ").append("(").append(bssid).append(")");
 
         if (venueName != null)
-            sb.append(" venueName: ").append(venueName.replace("\n", "\\n"));
+            sb.append(" venueName: ").append("(")
+              .append(venueName.replace("\n", "\\n")).append(")");
 
-        if (networkAuthType != null) {
+        if (networkAuthTypeList != null) {
             sb.append(" networkAuthType: ");
-            for (NetworkAuthType auth : networkAuthType)
+            for (NetworkAuthType auth : networkAuthTypeList)
                 sb.append("(").append(auth.toString()).append(")");
         }
 
-        if (roamingConsortium != null) {
+        if (roamingConsortiumList != null) {
             sb.append(" roamingConsortium: ");
-            for (String oi : roamingConsortium)
+            for (String oi : roamingConsortiumList)
                 sb.append("(").append(oi).append(")");
         }
 
@@ -308,21 +309,21 @@
               .append(ipAddrTypeAvailability.toString()).append(")");
         }
 
-        if (naiRealm != null) {
+        if (naiRealmList != null) {
             sb.append(" naiRealm: ");
-            for (NaiRealm realm : naiRealm)
+            for (NaiRealm realm : naiRealmList)
                 sb.append("(").append(realm.toString()).append(")");
         }
 
-        if (cellularNetwork != null) {
+        if (cellularNetworkList != null) {
             sb.append(" cellularNetwork: ");
-            for (CellularNetwork plmn : cellularNetwork)
+            for (CellularNetwork plmn : cellularNetworkList)
                 sb.append("(").append(plmn.toString()).append(")");
         }
 
-        if (domainName != null) {
+        if (domainNameList != null) {
             sb.append(" domainName: ");
-            for (String fqdn : domainName)
+            for (String fqdn : domainNameList)
                 sb.append("(").append(fqdn).append(")");
         }
 
@@ -334,9 +335,9 @@
             sb.append(" wanMetrics: ").append("(")
               .append(wanMetrics.toString()).append(")");
 
-        if (connectionCapability != null) {
+        if (connectionCapabilityList != null) {
             sb.append(" connectionCapability: ");
-            for (IpProtoPort ip : connectionCapability)
+            for (IpProtoPort ip : connectionCapabilityList)
                 sb.append("(").append(ip.toString()).append(")");
         }
 
@@ -355,21 +356,21 @@
         out.writeString(bssid);
         out.writeString(venueName);
 
-        if (networkAuthType == null) {
+        if (networkAuthTypeList == null) {
             out.writeInt(0);
         } else {
-            out.writeInt(networkAuthType.size());
-            for (NetworkAuthType auth : networkAuthType) {
+            out.writeInt(networkAuthTypeList.size());
+            for (NetworkAuthType auth : networkAuthTypeList) {
                 out.writeInt(auth.type);
                 out.writeString(auth.redirectUrl);
             }
         }
 
-        if (roamingConsortium == null) {
+        if (roamingConsortiumList == null) {
             out.writeInt(0);
         } else {
-            out.writeInt(roamingConsortium.size());
-            for (String oi : roamingConsortium)
+            out.writeInt(roamingConsortiumList.size());
+            for (String oi : roamingConsortiumList)
                 out.writeString(oi);
         }
 
@@ -379,32 +380,32 @@
             out.writeInt(ipAddrTypeAvailability.availability);
         }
 
-        if (naiRealm == null) {
+        if (naiRealmList == null) {
             out.writeInt(0);
         } else {
-            out.writeInt(naiRealm.size());
-            for (NaiRealm realm : naiRealm) {
+            out.writeInt(naiRealmList.size());
+            for (NaiRealm realm : naiRealmList) {
                 out.writeInt(realm.encoding);
                 out.writeString(realm.realm);
             }
         }
 
-        if (cellularNetwork == null) {
+        if (cellularNetworkList == null) {
             out.writeInt(0);
         } else {
-            out.writeInt(cellularNetwork.size());
-            for (CellularNetwork plmn : cellularNetwork) {
+            out.writeInt(cellularNetworkList.size());
+            for (CellularNetwork plmn : cellularNetworkList) {
                 out.writeString(plmn.mcc);
                 out.writeString(plmn.mnc);
             }
         }
 
 
-        if (domainName == null) {
+        if (domainNameList == null) {
             out.writeInt(0);
         } else {
-            out.writeInt(domainName.size());
-            for (String fqdn : domainName)
+            out.writeInt(domainNameList.size());
+            for (String fqdn : domainNameList)
                 out.writeString(fqdn);
         }
 
@@ -422,11 +423,11 @@
             out.writeInt(wanMetrics.lmd);
         }
 
-        if (connectionCapability == null) {
+        if (connectionCapabilityList == null) {
             out.writeInt(0);
         } else {
-            out.writeInt(connectionCapability.size());
-            for (IpProtoPort ip : connectionCapability) {
+            out.writeInt(connectionCapabilityList.size());
+            for (IpProtoPort ip : connectionCapabilityList) {
                 out.writeInt(ip.proto);
                 out.writeInt(ip.port);
                 out.writeInt(ip.status);
@@ -461,20 +462,20 @@
 
                     n = in.readInt();
                     if (n > 0) {
-                        p.networkAuthType = new ArrayList<NetworkAuthType>();
+                        p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
                         for (int i = 0; i < n; i++) {
                             NetworkAuthType auth = new NetworkAuthType();
                             auth.type = in.readInt();
                             auth.redirectUrl = in.readString();
-                            p.networkAuthType.add(auth);
+                            p.networkAuthTypeList.add(auth);
                         }
                     }
 
                     n = in.readInt();
                     if (n > 0) {
-                        p.roamingConsortium = new ArrayList<String>();
+                        p.roamingConsortiumList = new ArrayList<String>();
                         for (int i = 0; i < n; i++)
-                            p.roamingConsortium.add(in.readString());
+                            p.roamingConsortiumList.add(in.readString());
                     }
 
                     n = in.readInt();
@@ -485,31 +486,31 @@
 
                     n = in.readInt();
                     if (n > 0) {
-                        p.naiRealm = new ArrayList<NaiRealm>();
+                        p.naiRealmList = new ArrayList<NaiRealm>();
                         for (int i = 0; i < n; i++) {
                             NaiRealm realm = new NaiRealm();
                             realm.encoding = in.readInt();
                             realm.realm = in.readString();
-                            p.naiRealm.add(realm);
+                            p.naiRealmList.add(realm);
                         }
                     }
 
                     n = in.readInt();
                     if (n > 0) {
-                        p.cellularNetwork = new ArrayList<CellularNetwork>();
+                        p.cellularNetworkList = new ArrayList<CellularNetwork>();
                         for (int i = 0; i < n; i++) {
                             CellularNetwork plmn = new CellularNetwork();
                             plmn.mcc = in.readString();
                             plmn.mnc = in.readString();
-                            p.cellularNetwork.add(plmn);
+                            p.cellularNetworkList.add(plmn);
                         }
                     }
 
                     n = in.readInt();
                     if (n > 0) {
-                        p.domainName = new ArrayList<String>();
+                        p.domainNameList = new ArrayList<String>();
                         for (int i = 0; i < n; i++)
-                            p.domainName.add(in.readString());
+                            p.domainNameList.add(in.readString());
                     }
 
                     p.operatorFriendlyName = in.readString();
@@ -527,13 +528,13 @@
 
                     n = in.readInt();
                     if (n > 0) {
-                        p.connectionCapability = new ArrayList<IpProtoPort>();
+                        p.connectionCapabilityList = new ArrayList<IpProtoPort>();
                         for (int i = 0; i < n; i++) {
                             IpProtoPort ip = new IpProtoPort();
                             ip.proto = in.readInt();
                             ip.port = in.readInt();
                             ip.status = in.readInt();
-                            p.connectionCapability.add(ip);
+                            p.connectionCapabilityList.add(ip);
                         }
                     }
 
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index 55acbad..e7e6767 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -22,6 +22,8 @@
 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;
 
@@ -45,58 +47,53 @@
 
     /* Passpoint states values */
 
-    /** Passpoint is in an known state. This should only occur in boot time @hide */
+    /** Passpoint is in an unknown state. This should only occur in boot time */
     public static final int PASSPOINT_STATE_UNKNOWN = 0;
 
-    /** Passpoint is disabled. This occurs when wifi is disabled. @hide */
+    /** Passpoint is disabled. This occurs when wifi is disabled */
     public static final int PASSPOINT_STATE_DISABLED = 1;
 
-    /** Passpoint is enabled and in discovery state. @hide */
+    /** Passpoint is enabled and in discovery state */
     public static final int PASSPOINT_STATE_DISCOVERY = 2;
 
-    /** Passpoint is enabled and in access state. @hide */
+    /** Passpoint is enabled and in access state */
     public static final int PASSPOINT_STATE_ACCESS = 3;
 
-    /** Passpoint is enabled and in provisioning state. @hide */
+    /** Passpoint is enabled and in provisioning state */
     public static final int PASSPOINT_STATE_PROVISION = 4;
 
     /* Passpoint callback error codes */
 
-    /** Indicates that the operation failed due to an internal error @hide */
-    public static final int ERROR = 0;
+    /** Indicates that the operation failed due to an internal error */
+    public static final int REASON_ERROR = 0;
 
-    /** Indicates that the operation failed because wifi is disabled @hide */
-    public static final int WIFI_DISABLED = 1;
+    /** Indicates that the operation failed because wifi is disabled */
+    public static final int REASON_WIFI_DISABLED = 1;
 
-    /** Indicates that the operation failed because the framework is busy @hide */
-    public static final int BUSY = 2;
+    /** Indicates that the operation failed because the framework is busy */
+    public static final int REASON_BUSY = 2;
+
+    /** Indicates that the operation failed because parameter is invalid */
+    public static final int REASON_INVALID_PARAMETER = 3;
+
+    /** Indicates that the operation failed because the server is not trusted */
+    public static final int REASON_NOT_TRUSTED = 4;
 
     /**
      * protocol supported for Passpoint
-     * @hide
      */
     public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
 
     /**
      * protocol supported for Passpoint
-     * @hide
      */
     public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
 
     /* Passpoint broadcasts */
 
     /**
-     * Broadcast intent action indicating that Passpoint online sign up is
-     * avaiable.
-     * @hide
-     */
-    public static final String PASSPOINT_OSU_AVAILABLE =
-            "android.net.wifi.passpoint.OSU_AVAILABLE";
-
-    /**
      * Broadcast intent action indicating that the state of Passpoint
      * connectivity has changed
-     * @hide
      */
     public static final String PASSPOINT_STATE_CHANGED_ACTION =
             "android.net.wifi.passpoint.STATE_CHANGE";
@@ -104,7 +101,6 @@
     /**
      * Broadcast intent action indicating that the saved Passpoint credential
      * list has changed
-     * @hide
      */
     public static final String PASSPOINT_CRED_CHANGED_ACTION =
             "android.net.wifi.passpoint.CRED_CHANGE";
@@ -112,21 +108,18 @@
     /**
      * Broadcast intent action indicating that Passpoint online sign up is
      * avaiable.
-     * @hide
      */
     public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
             "android.net.wifi.passpoint.OSU_AVAILABLE";
 
     /**
      * Broadcast intent action indicating that user remediation is required
-     * @hide
      */
     public static final String PASSPOINT_USER_REM_REQ_ACTION =
             "android.net.wifi.passpoint.USER_REM_REQ";
 
     /**
      * Interface for callback invocation when framework channel is lost
-     * @hide
      */
     public interface ChannelListener {
         /**
@@ -138,14 +131,13 @@
 
     /**
      * Interface for callback invocation on an application action
-     * @hide
      */
     public interface ActionListener {
         /** The operation succeeded */
         public void onSuccess();
 
         /**
-         * * The operation failed
+         * The operation failed
          *
          * @param reason The reason for failure could be one of
          *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
@@ -155,7 +147,6 @@
 
     /**
      * Interface for callback invocation when doing OSU or user remediation
-     * @hide
      */
     public interface OsuRemListener {
         /** The operation succeeded */
@@ -171,11 +162,11 @@
 
         /**
          * Browser launch is requried for user interaction. When this callback
-         * is called, app should launch browser / webview to the given URL.
+         * is called, app should launch browser / webview to the given URI.
          *
-         * @param url URL for browser launch
+         * @param uri URI for browser launch
          */
-        public void onBrowserLaunch(String url);
+        public void onBrowserLaunch(String uri);
 
         /**
          * When this is called, app should dismiss the previously lanched browser.
@@ -187,7 +178,6 @@
      * A channel that connects the application to the wifi passpoint framework.
      * Most passpoint operations require a Channel as an argument.
      * An instance of Channel is obtained by doing a call on {@link #initialize}
-     * @hide
      */
     public static class Channel {
         private final static int INVALID_LISTENER_KEY = 0;
@@ -288,7 +278,8 @@
 
             @Override
             public void handleMessage(Message message) {
-                Object listener = getListener(message.arg2, false);
+                Object listener = null;
+
                 switch (message.what) {
                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
                         if (mChannelListener != null) {
@@ -300,6 +291,7 @@
                     case REQUEST_ANQP_INFO_SUCCEEDED:
                         WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
                         anqpRequestFinish(result);
+                        listener = getListener(message.arg2, false);
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -307,6 +299,7 @@
 
                     case REQUEST_ANQP_INFO_FAILED:
                         anqpRequestFinish((ScanResult) message.obj);
+                        listener = getListener(message.arg2, false);
                         if (listener == null)
                             getListener(message.arg2, true);
                         if (listener != null) {
@@ -314,6 +307,31 @@
                         }
                         break;
 
+                    case START_OSU_SUCCEEDED:
+                        listener = getListener(message.arg2, true);
+                        if (listener != null) {
+                            ((OsuRemListener) listener).onSuccess();
+                        }
+                        break;
+
+                    case START_OSU_FAILED:
+                        listener = getListener(message.arg2, true);
+                        if (listener != null) {
+                            ((OsuRemListener) listener).onFailure(message.arg1);
+                        }
+                        break;
+
+                    case START_OSU_BROWSER:
+                        listener = getListener(message.arg2, true);
+                        if (listener != null) {
+                            ParcelableString str = (ParcelableString) message.obj;
+                            if (str == null || str.string == null)
+                                ((OsuRemListener) listener).onBrowserDismiss();
+                            else
+                                ((OsuRemListener) listener).onBrowserLaunch(str.string);
+                        }
+                        break;
+
                     default:
                         Log.d(TAG, "Ignored " + message);
                         break;
@@ -323,25 +341,46 @@
 
     }
 
+    public static class ParcelableString implements Parcelable {
+        public String string;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(string);
+        }
+
+        public static final Parcelable.Creator<ParcelableString> CREATOR =
+                new Parcelable.Creator<ParcelableString>() {
+                    @Override
+                    public ParcelableString createFromParcel(Parcel in) {
+                        ParcelableString ret = new ParcelableString();
+                        ret.string = in.readString();
+                        return ret;
+                    }
+                    @Override
+                    public ParcelableString[] newArray(int size) {
+                        return new ParcelableString[size];
+                    }
+        };
+    }
+
     private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
 
-    /** @hide */
-    public static final int REQUEST_ANQP_INFO = BASE + 1;
-
-    /** @hide */
-    public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
-
-    /** @hide */
-    public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
-
-    /** @hide */
-    public static final int REQUEST_OSU_INFO = BASE + 4;
-
-    /** @hide */
-    public static final int REQUEST_OSU_INFO_FAILED = BASE + 5;
-
-    /** @hide */
-    public static final int REQUEST_OSU_INFO_SUCCEEDED = BASE + 6;
+    public static final int REQUEST_ANQP_INFO                   = BASE + 1;
+    public static final int REQUEST_ANQP_INFO_FAILED            = BASE + 2;
+    public static final int REQUEST_ANQP_INFO_SUCCEEDED         = BASE + 3;
+    public static final int REQUEST_OSU_ICON                    = BASE + 4;
+    public static final int REQUEST_OSU_ICON_FAILED             = BASE + 5;
+    public static final int REQUEST_OSU_ICON_SUCCEEDED          = BASE + 6;
+    public static final int START_OSU                           = BASE + 7;
+    public static final int START_OSU_BROWSER                   = BASE + 8;
+    public static final int START_OSU_FAILED                    = BASE + 9;
+    public static final int START_OSU_SUCCEEDED                 = BASE + 10;
 
     private Context mContext;
     IWifiPasspointManager mService;
@@ -350,7 +389,6 @@
      * TODO: doc
      * @param context
      * @param service
-     * @hide
      */
     public WifiPasspointManager(Context context, IWifiPasspointManager service) {
         mContext = context;
@@ -368,7 +406,6 @@
      * @return Channel instance that is necessary for performing any further
      *         passpoint operations
      *
-     * @hide
      */
     public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
         Messenger messenger = getMessenger();
@@ -387,8 +424,6 @@
     /**
      * STOPSHIP: temp solution, should use supplicant manager instead, check
      * with b/13931972
-     *
-     * @hide
      */
     public Messenger getMessenger() {
         try {
@@ -398,7 +433,6 @@
         }
     }
 
-    /** @hide */
     public int getPasspointState() {
         try {
             return mService.getPasspointState();
@@ -407,7 +441,6 @@
         }
     }
 
-    /** @hide */
     public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
             ActionListener listener) {
         Log.d(TAG, "requestAnqpInfo start");
@@ -434,14 +467,16 @@
         Log.d(TAG, "requestAnqpInfo end");
     }
 
-    /** @hide */
     public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
             int resolution, ActionListener listener) {
     }
 
-    /** @hide */
     public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
-        return null;
+        try {
+            return mService.requestCredentialMatch(requested);
+        } catch (RemoteException e) {
+            return null;
+        }
     }
 
     /**
@@ -450,7 +485,7 @@
      *
      * @return The list of credentials
      */
-    public List<WifiPasspointCredential> getSavedCredentials() {
+    public List<WifiPasspointCredential> getCredentials() {
         return null;
     }
 
@@ -486,21 +521,21 @@
         return true;
     }
 
-    /** @hide */
-    public void startOsu(Channel c, WifiPasspointOsuProvider selected, OsuRemListener listener) {
-
+    public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
+        Log.d(TAG, "startOsu start");
+        checkChannel(c);
+        int key = c.putListener(listener);
+        c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
+        Log.d(TAG, "startOsu end");
     }
 
-    /** @hide */
-    public void startUserRemediation(Channel c, OsuRemListener listener) {
+    public void startRemediation(Channel c, OsuRemListener listener) {
     }
 
-    /** @hide */
-    public void connect(WifiPasspointPolicy selected) {
+    public void connect(WifiPasspointPolicy policy) {
     }
 
     private static void checkChannel(Channel c) {
-        if (c == null)
-            throw new IllegalArgumentException("Channel needs to be initialized");
+        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
     }
 }
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
index f40dc4f..b54b70c 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
@@ -87,12 +87,12 @@
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
-        sb.append("SSID: ").append(ssid);
+        sb.append("SSID: ").append("<").append(ssid).append(">");
         if (friendlyName != null)
-            sb.append(" friendlyName: ").append(friendlyName);
+            sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
         if (serverUri != null)
-            sb.append(" serverUri: ").append(serverUri);
-        sb.append(" osuMethod: ").append(osuMethod);
+            sb.append(" serverUri: ").append("<").append(serverUri).append(">");
+        sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
         if (iconFileName != null) {
             sb.append(" icon: <").append(iconWidth).append("x")
                     .append(iconHeight).append(" ")
@@ -100,9 +100,9 @@
                     .append(iconFileName).append(">");
         }
         if (osuNai != null)
-            sb.append(" osuNai: ").append(osuNai);
+            sb.append(" osuNai: ").append("<").append(osuNai).append(">");
         if (osuService != null)
-            sb.append(" osuService: ").append(osuService);
+            sb.append(" osuService: ").append("<").append(osuService).append(">");
         return sb.toString();
     }
 
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
index 9fccf0a..f84ac88 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
@@ -16,10 +16,18 @@
 
 package android.net.wifi.passpoint;
 
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.ScanResult;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.security.Credentials;
 import android.util.Log;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+
 /** @hide */
 public class WifiPasspointPolicy implements Parcelable {
 
@@ -43,6 +51,20 @@
     private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
     private boolean mIsHomeSp;
 
+    private final String INT_PRIVATE_KEY = "private_key";
+    private final String INT_PHASE2 = "phase2";
+    private final String INT_PASSWORD = "password";
+    private final String INT_IDENTITY = "identity";
+    private final String INT_EAP = "eap";
+    private final String INT_CLIENT_CERT = "client_cert";
+    private final String INT_CA_CERT = "ca_cert";
+    private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
+    private final String INT_SIM_SLOT = "sim_slot";
+    private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
+    private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+    private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
+    private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
+
     /** @hide */
     public WifiPasspointPolicy(String name, String ssid,
             String bssid, WifiPasspointCredential pc,
@@ -89,7 +111,7 @@
     }
 
     /** @hide */
-    public boolean getHomeSp() {
+    public boolean isHomeSp() {
         return mIsHomeSp;
     }
 
@@ -121,6 +143,142 @@
         return mRoamingPriority;
     }
 
+    public WifiConfiguration createWifiConfiguration() {
+        WifiConfiguration wfg = new WifiConfiguration();
+        if (mBssid != null) {
+            Log.d(TAG, "create bssid:" + mBssid);
+            wfg.BSSID = mBssid;
+        }
+
+        if (mSsid != null) {
+            Log.d(TAG, "create ssid:" + mSsid);
+            wfg.SSID = mSsid;
+        }
+        //TODO: 1. add pmf configuration
+        //      2. add ocsp configuration
+        //      3. add eap-sim configuration
+        /*Key management*/
+        wfg.status = WifiConfiguration.Status.ENABLED;
+        wfg.allowedKeyManagement.clear();
+        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+
+        /*Group Ciphers*/
+        wfg.allowedGroupCiphers.clear();
+        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+
+        /*Protocols*/
+        wfg.allowedProtocols.clear();
+        wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+        wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+
+        Class[] enterpriseFieldArray  = WifiConfiguration.class.getClasses();
+        Class<?> enterpriseFieldClass = null;
+
+
+        for(Class<?> myClass : enterpriseFieldArray) {
+            if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
+                enterpriseFieldClass = myClass;
+                break;
+            }
+        }
+        Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
+
+
+        Field anonymousId = null, caCert = null, clientCert = null,
+              eap = null, identity = null, password = null,
+              phase2 = null, privateKey =  null;
+
+        Field[] fields = WifiConfiguration.class.getFields();
+
+
+        for (Field tempField : fields) {
+            if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
+                anonymousId = tempField;
+                Log.d(TAG, "field " + anonymousId.getName() );
+            } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
+                caCert = tempField;
+            } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
+                clientCert = tempField;
+                Log.d(TAG, "field " + clientCert.getName() );
+            } else if (tempField.getName().trim().equals(INT_EAP)) {
+                eap = tempField;
+                Log.d(TAG, "field " + eap.getName() );
+            } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
+                identity = tempField;
+                Log.d(TAG, "field " + identity.getName() );
+            } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
+                password = tempField;
+                Log.d(TAG, "field " + password.getName() );
+            } else if (tempField.getName().trim().equals(INT_PHASE2)) {
+                phase2 = tempField;
+                Log.d(TAG, "field " + phase2.getName() );
+
+            } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
+                privateKey = tempField;
+            }
+        }
+
+
+        Method setValue = null;
+
+        for(Method m: enterpriseFieldClass.getMethods()) {
+            if(m.getName().trim().equals("setValue")) {
+                Log.d(TAG, "method " + m.getName() );
+                setValue = m;
+                break;
+            }
+        }
+
+        try {
+            // EAP
+            String eapmethod = mCredential.getType();
+            Log.d(TAG, "eapmethod:" + eapmethod);
+            setValue.invoke(eap.get(wfg), eapmethod);
+
+            // Username, password, EAP Phase 2
+            if ("TTLS".equals(eapmethod)) {
+                setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
+                setValue.invoke(identity.get(wfg), mCredential.getUserName());
+                setValue.invoke(password.get(wfg), mCredential.getPassword());
+                setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
+            }
+
+            // EAP CA Certificate
+            String cacertificate = null;
+            String rootCA = mCredential.getCaRootCertPath();
+            if (rootCA == null){
+                cacertificate = null;
+            } else {
+                cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
+            }
+            Log.d(TAG, "cacertificate:" + cacertificate);
+            setValue.invoke(caCert.get(wfg), cacertificate);
+
+            //User certificate
+            if ("TLS".equals(eapmethod)) {
+                String usercertificate = null;
+                String privatekey = null;
+                String clientCertPath = mCredential.getClientCertPath();
+                if (clientCertPath != null){
+                    privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
+                    usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
+                }
+                Log.d(TAG, "privatekey:" + privatekey);
+                Log.d(TAG, "usercertificate:" + usercertificate);
+                if (privatekey != null && usercertificate != null) {
+                    setValue.invoke(privateKey.get(wfg), privatekey);
+                    setValue.invoke(clientCert.get(wfg), usercertificate);
+                }
+            }
+        } catch (Exception e) {
+            Log.d(TAG, "createWifiConfiguration err:" + e);
+        }
+
+        return wfg;
+    }
+
     /** {@inheritDoc} @hide */
     public int compareTo(WifiPasspointPolicy another) {
         Log.d(TAG, "this:" + this);
@@ -128,11 +286,11 @@
 
         if (another == null) {
             return -1;
-        } else if (this.mIsHomeSp == true && another.getHomeSp() == false) {
+        } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
             //home sp priority is higher then roaming
             Log.d(TAG, "compare HomeSP  first, this is HomeSP, another isn't");
             return -1;
-        } else if ((this.mIsHomeSp == true && another.getHomeSp() == true)) {
+        } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
             Log.d(TAG, "both HomeSP");
             //if both home sp, compare credential priority
             if (this.mCredentialPriority < another.getCredentialPriority()) {
@@ -160,7 +318,7 @@
             } else {
                 return 1;
             }
-        } else if ((this.mIsHomeSp == false && another.getHomeSp() == false)) {
+        } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
             Log.d(TAG, "both RoamingSp");
             //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
             if (this.mRoamingPriority < another.getRoamingPriority()) {